1

我有以下用于创建 EFCodeFirst 数据库的 C# 代码:

enum MemberOfGroupDiscriminator { MemberOfGroup, GroupMemberOfGroup, UserMemberOfGroup }
public class MemberOfGroup
{
    public int Member_ID { get; set; }
    public int Group_ID { get; set; }
}

public class GroupMemberOfGroup : MemberOfGroup { }
public class UserMemberOfGroup : MemberOfGroup { }

public class User : WSSCSDevModel, IUser
{
    public int LoginCount { get; set; }
    public DateTime LastLogin { get; set; }
    public virtual ICollection<MemberOfGroup> Memberships { get; set; }
}

public class Group : WSSCSDevModel,  IGroup
{
    public string Name { get; set; }
}

这在 fluent API 中创建数据库:

        ModelBuilder.Entity<MemberOfGroup>()
            .HasKey(k => new { k.Member_ID, k.Group_ID })
            .Map<MemberOfGroup>(m => m.Requires("OfGroupType")
                .HasValue((byte)MemberOfGroupDiscriminator.MemberOfGroup))
            .Map<UserMemberOfGroup>(m => m.Requires("OfGroupType")
                .HasValue((byte)MemberOfGroupDiscriminator.UserMemberOfGroup))
            .Map<UserMemberOfGroup>(m => m.Properties(p => p.Member_ID = UserAddition.))
            .Map<GroupMemberOfGroup>(m => m.Requires("OfGroupType")
                .HasValue((byte)MemberOfGroupDiscriminator.GroupMemberOfGroup))
            .ToTable("MemberOfGroup");

我的想法是让用户和组能够形成组。所以 GroupB 可能是 GroupA 加上另外 1 个人。我的问题是,当判别器说要这样做时,我如何强制框架检查 Member_ID 是否是 User 的键,以及使用 Group。

顺便说一句,用户和组实体具有 int ID {get; 放; } 在他们的父类中声明。

谢谢!

编辑:

重新审视这一点,我现在在将成员添加到组时遇到问题。这是我的代码:

public class WSSCSDevDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Group> Groups { get; set; }

    protected override void OnModelCreating(DbModelBuilder ModelBuilder)
    {
        ModelBuilder.Entity<User>().ToTable("Users");
        ModelBuilder.Entity<Group>().ToTable("Groups");

        ModelBuilder.Entity<MemberOfGroup>()
            .HasKey(m => m.ID)
            .Map<GroupMemberOfGroup>(g => g.Requires("OfType")
                .HasValue((byte)MemberOfGroupDiscriminator.GroupMemberOfGroup))
            .Map<UserMemberOfGroup>(u => u.Requires("OfType")
                .HasValue((byte)MemberOfGroupDiscriminator.UserMemberOfGroup));

        ModelBuilder.Entity<User>()
            .HasMany(u => u.MemberOf)
            .WithRequired(m => m.MemberUser)
            .HasForeignKey(m => m.MemberUser_ID)
            .WillCascadeOnDelete(false);

        ModelBuilder.Entity<Group>()
            .HasMany(g => g.MemberOf)
            .WithRequired(m => m.MemberGroup)
            .HasForeignKey(m => m.MemberGroup_ID)
            .WillCascadeOnDelete(false);

        ModelBuilder.Entity<Group>()
            .HasMany(u => u.Members)
            .WithRequired(m => m.Group)
            .HasForeignKey(m => m.Group_ID);
    }
}

public class User : WSSCSDevModel, IUser
{
    public int LoginCount { get; set; }
    public DateTime LastLogin { get; set; }
    public virtual ICollection<UserMemberOfGroup> MemberOf { get; set; }
    public virtual ICollection<MemberOfGroup> Memberships { get; set; }
}

public class Group : WSSCSDevModel,  IGroup
{
    public string Name { get; set; }
    public virtual ICollection<GroupMemberOfGroup> MemberOf { get; set; }
    public virtual ICollection<MemberOfGroup> Members { get; set; }
}



public class MemberOfGroup
{
    public int? Group_ID { get; set; }
    virtual public Group Group { get; set; }
}

public class GroupMemberOfGroup : MemberOfGroup 
{
    public int? MemberGroup_ID { get; set; }
    virtual public Group MemberGroup { get; set; }
}

public class UserMemberOfGroup : MemberOfGroup 
{
    public int? MemberUser_ID { get; set; }
    virtual public User MemberUser { get; set; }
}

同样,Group 和 User 父类定义 int ID {get;set;}

这是我的控制器中将用户添加到组的代码:

        if(model.MemberOf_IDs != null)
        {
            Repository<User> UserRepo = new Repository<User>();
            User ToEdit = UserRepo.GetById(model.User_ID);
            foreach (UserMemberOfGroup Membership in ToEdit.MemberOf)
            {
                Membership.Group.Members.Remove(Membership);
            }
            ToEdit.MemberOf = new List<UserMemberOfGroup>();
            Repository<Group> GroupRepo = new Repository<Group>();
            string[] Delims = new string[1];
            Delims[0] = ";";
            List<int> IDs = model.MemberOf_IDs.Split(Delims, 
                StringSplitOptions.RemoveEmptyEntries).Select(id => Convert.ToInt32(id)).ToList();
            foreach(int ID in IDs)
            {
                Group ToAddTo = GroupRepo.GetById(ID);
                ToEdit.MemberOf.Add(ToAddTo.AddMember(ToEdit));
            }

            GroupRepo.Save();
        }

我知道这甚至不是最好的方法,但它说明了我的问题。顺便说一句,Repository<> 类共享 DBContext。所以本质上,.Save on one 就是 .Save on them all。这工作正常。

此代码采用分号分隔的组 ID 字符串,并将用户添加到其中。但是,我得到了这个例外:

A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in     System.Data.dll

Additional information: Cannot insert the value NULL into column 'Group_ID', table 'CSProSuiteIndia.dbo.MemberOfGroups'; column does not allow nulls. UPDATE fails.
The statement has been terminated.

我不明白为什么要将 Group_ID 更改为 NULL。我将 Group_ID 声明为 int?,所以我认为它应该可以为空。这里发生了什么事?

4

1 回答 1

1

您想要的是在用户和组之间动态切换外键引用。你可以在单列的数据库中做到这一点吗?你不能,所以你也不能在 ORM 中这样做。如果要强制执行完整性,则必须Member_ID从父级移动到子级并为其映射单独的关系。它将在 db 中创建两列,每列都有自己的 FK:

public abstract class Principal
{
    public int Id { get; set; }
}

public class User : Principal
{
    public string Login { get; set; }
    public virtual ICollection<UserMemberOfGroup> MemberOf { get; set; }
}

public class Group : Principal
{
    public string Name { get; set; }
    public virtual ICollection<GroupMemberOfGroup> MemberOf { get; set; }
    public virtual ICollection<MemberOfGroup> Members { get; set; }
}

public enum MemberOfGroupDiscriminator
{
    MemberOfGroup, 
    GroupMemberOfGroup, 
    UserMemberOfGroup
}

public abstract class MemberOfGroup
{
    public int Id { get; set; }
    public int GroupId { get; set; }
    public Group Group { get; set; }
}

public class GroupMemberOfGroup : MemberOfGroup
{
    public int MemberGroupId { get; set; }
    public Group MemberGroup { get; set; }
}

public class UserMemberOfGroup : MemberOfGroup
{
    public int UserId { get; set; }
    public User User { get; set; }
}

public class Context : DbContext
{
    public DbSet<Principal> Principals { get; set; }
    public DbSet<MemberOfGroup> MembersOfGroups { get; set; }

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

        modelBuilder.Entity<Principal>()
            .HasKey(p => p.Id)
            .Map<User>(u => u.Requires("Type").HasValue("U"))
            .Map<Group>(p => p.Requires("Type").HasValue("G"));

        modelBuilder.Entity<MemberOfGroup>()
            .HasKey(m => m.Id)
            .Map<GroupMemberOfGroup>(g => g.Requires("Type").HasValue("G"))
            .Map<UserMemberOfGroup>(u => u.Requires("Type").HasValue("U"));

        modelBuilder.Entity<User>()
            .HasMany(u => u.MemberOf)
            .WithRequired(m => m.User)
            .HasForeignKey(m => m.UserId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Group>()
            .HasMany(u => u.MemberOf)
            .WithRequired(m => m.MemberGroup)
            .HasForeignKey(m => m.MemberGroupId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Group>()
            .HasMany(u => u.Members)
            .WithRequired(m => m.Group)
            .HasForeignKey(m => m.GroupId);
    }
}
于 2011-04-01T19:51:51.173 回答