实体框架删除了太多条目-C#

时间:2018-08-08 06:26:22

标签: c# sql entity-framework entity-framework-6

我很讨厌Entity Framework。它应该更容易,更快捷,但是太可怕了。

我正在对两个非常简单的表使用数据库优先方法。带有UserId的{​​{1}}表,位于Username上的主键和自动增量,以及带有Id和{{1}的Permission表},两列的主键以及从permissionnameuserid的关系。

这是我授予和撤消权限的代码:

userid

user.id属性绑定到一个复选框。

   public bool ContributionMarginCustomer
    {
        get => GetPermission(_contributionmarginCustomer);
        set => SetPermission(value, _contributionmarginCustomer);
    }

授予权限非常有用。

使用ContributionMarginCustomer删除权限会将其从数据库中的每个用户中删除。

我不了解这种行为。你们有吗?

谢谢

编辑: 方便用户

enter image description here

之前的权限表:

enter image description here

使用userId 15和键private void SetPermission(bool permissionIsGranted, string key) { var permissionStatus = permissionIsGranted ? PermissionStatus.Granted : PermissionStatus.Revoked; using (var entity = new KundeninfoEntities()) { var user = entity.Users.Single(x => x.Id == _user.Id); var existingPermission = user.Permissions.SingleOrDefault(x => x.Name == key); switch (permissionStatus) { case PermissionStatus.Granted: if (existingPermission == null) { user.Permissions.Add(new Permission { Name = key }); entity.SaveChanges(); } break; case PermissionStatus.Revoked: if (existingPermission != null) { entity.Permissions.Remove(existingPermission); entity.SaveChanges(); } break; } _permissions = entity.Permissions .Where(x => x.UserId == _user.Id) .ToList(); } } 删除它后的权限表

enter image description here

编辑2:解决方案

我将权限表更改为仅一列作为主键。 这意味着新的权限表具有三列:Id(自动增量),Name和UserId,具有唯一的name和userid键。

上面的代码现在可以工作了,但是我对此并不满意。

4 个答案:

答案 0 :(得分:2)

在第二种情况下,您不是从用户中删除许可,而是从实体(基本上是整个用户列表)中删除许可。 更改为

case PermissionStatus.Revoked:
                if (existingPermission != null)
                {
                    user.Permissions.Remove(existingPermission);
                    entity.SaveChanges();
                }
                break;

答案 1 :(得分:1)

将权限的状态设置为“已删除”。

var existingPermission = user.Permissions.SingleOrDefault(x => x.Name == key);
//your other code here.
entity.Entry(existingPermission).State = EntityState.Removed;
entity.SaveChanges();

答案 2 :(得分:1)

在我看来,您的数据库不够规范。恕我直言,这会使您的代码更加困难,并在授予/拒绝权限时引起问题。

您有UsersPermissions。每个User都有零个或多个Permissions,每个Permission被授予零个或多个Users。标准的多对多关系。

实体框架中的多对多设计如下:

class User
{
    public int Id {get; set;}

    // every user has zero or more Permissions (many-to-many)
    public virtual ICollection<Permission> Permissions {get; set;}

    ...
}
class Permission
{
    public int Id {get; set;}

    // every Permission is granted to zero or more Users (many-to-many)
    public virtual ICollection<User> Users {get; set;}
    ...
}
class MyDbContext : DbContext
{
     public DbSet<User> Users {get; set;}
     public DbSet<Permission> Permissions {get; set;}
}

这是实体框架所需要知道的,您设计了多对多关系。它将创建“用户和权限”表,并将创建(组)联接所需的联结表,当您要检索“授予用户的许可”或“具有某些许可的用户”时,需要完成此联接表

但是,您没有在代码中使用此联结表,而是使用ICollection。实体框架足够聪明,可以理解联结表需要使用(Group)联结,并将执行正确的联结

我将为DbContext创建几个扩展功能:

static void GrantPermission(this MyDbContext dbContext, User user, int permissionId)
{
    // TODO: check input parameters
    var permissionToGrant = dbContext.Permissions
        .Where(permission => permission.Id == permissionId)
        .FirstOrDefault();
    // TODO: decide what to do if not found
    user.Permissions.Add(permissionToGrant);
    var userToChange = dbContext.Users
}
static void GrantPermission(this MyDbContext dbContext, Permission permission, int userId)
{
     // TODO: check input parameters
     var userToGrantPermission = dbContext.Users
         .Where(user => user.Id == userId)
         .FirstToDefault();
      // TODO: decide what to do if not found
      permission.Users.Add(userToGrantPermission);
}

如果需要,按名称授予权限:

static void GrantPermission(this MyDbContext dbContext, User user, string permissionName)
{
    // TODO: check input parameters
    var permissionToGrant = dbContext.Permissions
        .Where(permission => permission.Name == permissionName)
        .FirstOrDefault();
    // TODO: decide what to do if not found
    user.Permissions.Add(permissionToGrant);
    var userToChange = dbContext.Users
}

拒绝权限:

static void GrantPermission(this MyDbContext dbContext, User user, string permissionName)
{
    // TODO: check input parameters
    var permissionToDeny = dbContext.Permissions
        .Where(permission => permission.Name == permissionName)
        .FirstOrDefault();
    if (permissionToDeny != null)
    {
         user.Permissions.Remove(permissionToDeny);
    }
    // else: user does not have this Permission; do nothing
}

// TODO: if desired: add function with userId and permissionName

用法:

using (var dbContext = new MyDbContext()
{
     int userId = ...
     string permissionName = ...
     dbContext.GrantPermission(userId, permissionName);
     dbContext.SaveChanges();
}

答案 3 :(得分:1)

我尽了最大的努力来重现问题,但我做不到。

我坚信,您举报行为的原因是SetPermission()未被认为是您的思维方式。

这是我的代码及其产生的输出。对SetPermission()方法的唯一更改是使其保持静态,以便使我的代码简短,但不应更改功能。

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace EFTest
{
   public class Program
   {
      static void Main( string[] args )
      {
         Database.SetInitializer( new DropCreateDatabaseAlways<EFTestContext>() );

         User userHans;
         User userFranz;

         var permissionA = "A";
         var permissionB = "B";

         using( var context = new EFTestContext() )
         {
            userHans = context.Users.Add( new User() { Name = "Hans" } );   // Id = 1
            userFranz = context.Users.Add( new User() { Name = "Franz" } ); // Id = 2
            context.SaveChanges();
         }

         SetPermission( userHans.Id, true, permissionA );
         SetPermission( userHans.Id, true, permissionB );
         SetPermission( userFranz.Id, true, permissionA );
         SetPermission( userFranz.Id, true, permissionB );
         ListAllPermissions();
         // 1: A
         // 1: B
         // 2: A
         // 2: B

         SetPermission( userFranz.Id, false, permissionA );    
         ListAllPermissions();
         // 1: A
         // 1: B
         // 2: B

         SetPermission( userHans.Id, false, permissionB );    
         ListAllPermissions();
         // 1: A
         // 2: B    
      }

      enum PermissionStatus
      {
         Granted,
         Revoked,
      }

      private static void ListAllPermissions()
      {
         using( var context = new EFTestContext() )
         {
            foreach( var permission in context.Permissions )
            {
               Console.WriteLine( $"{permission.UserId}: {permission.Name}" );
            }
         }
         Console.ReadLine();
      }

      private static IList<Permission> SetPermission( int userId, bool permissionIsGranted, string key )
      {
         var permissionStatus = permissionIsGranted ? PermissionStatus.Granted : PermissionStatus.Revoked;

         using( var entity = new EFTestContext() )
         {
            var user = entity.Users.Single( x => x.Id == userId );
            var existingPermission = user.Permissions.SingleOrDefault( x => x.Name == key );

            switch( permissionStatus )
            {
               case PermissionStatus.Granted:
                  if( existingPermission == null )
                  {
                     user.Permissions.Add( new Permission { Name = key } );
                     entity.SaveChanges();
                  }
                  break;

               case PermissionStatus.Revoked:
                  if( existingPermission != null )
                  {
                     entity.Permissions.Remove( existingPermission );
                     entity.SaveChanges();
                  }
                  break;
            }

            var permissions = entity.Permissions
                                    .Where( x => x.UserId == userId )
                                    .ToList();

            return permissions;
         }
      }
   }
}

出于完整性考虑,我的情况是

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

namespace EFTest
{
   public class EFTestContext : DbContext
   {
      public virtual DbSet<User> Users { get; set; }
      public virtual DbSet<Permission> Permissions { get; set; }

      protected override void OnModelCreating( DbModelBuilder modelBuilder )
      {
         base.OnModelCreating( modelBuilder );
      }
   }

   public class User
   {
      [Key]
      public int Id { get; set; }
      public string Name { get; set; }

      public virtual ICollection<Permission> Permissions { get; set; }
   }

   public class Permission
   {
      [Key, Column( Order = 1 )]
      public string Name { get; set; }
      [Key, Column( Order = 2 ), ForeignKey( nameof( User ) )]
      public int UserId { get; set; }

      public virtual User User { get; set; }
   }
}