1

我有EFCodeFirst數據庫創建下面的C#代碼:如何在ASP.net EFCodeFirst中使用判別式設置外鍵約束?

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; } 
} 

這在流利的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加上另一個人。我的問題是,我該如何強制框架檢查Member_ID是判別者說的這個用戶和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; } 
} 

同樣,組和用戶的父類定義INT ID {獲取;集;}

這裏的代碼在我的控制器,將用戶添加到組:

 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(); 
     } 

我知道這甚至不是最好的方式,但它說明了我的問題。順便說一下,存儲庫<>類共享DBContext。所以,基本上,保存一個就是。保存所有的東西。這工作正常。

此代碼以分號分隔字符串的組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 ?,所以它應該是可空的,我會想。這裏發生了什麼事?

回答

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); 
    } 
} 
+0

我做了類似的事情,我的解決方案很快就會出現。我印象中框架本身可以執行我所說的「動態外鍵」。是否有可能不使用MemberOfGroup.ID作爲該表的主鍵,並使用組,用戶和類型字段的組合? – TheTFo 2011-04-01 21:26:46

+0

我認爲組合鍵必須具有父實體中的所有屬性,但我沒有嘗試。另外'Type'不能是鍵的一部分,因爲它不是一個屬性。 – 2011-04-01 21:33:49