EF 5复合键与其他实体有很多关系

时间:2013-04-16 17:35:18

标签: c# entity-framework

在下面的代码中,我首先使用EF代码来设置我的数据库模型。

CaseCommunication实体具有包含Id列的复合键。如果我让EF完成工作,尽管有Many()规范,它仍会尝试将此列用作另一个实体的FK:

HasRequired(x => x.Case).WithMany(x => x.Communications);
HasOptional(x => x.FirstReadBy).WithMany();

要获得正确的模型,我必须明确设置FK(请阅读代码中的注释)。

HasRequired(x => x.Case).WithMany(x => x.Communications).Map(x => x.MapKey("Case_Id"));
HasOptional(x => x.FirstReadBy).WithMany().Map(x => x.MapKey("FirstReadBy_Id"));

如果我不使用复合键,那么所有都可以正常工作而不使用Map()。

我的问题是:EF的逻辑是什么?或者说另一种方式,我错过了什么?

using System;
using System.Linq;
using System.Data.Entity;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
using System.Data.Objects.SqlClient;
using System.ComponentModel.DataAnnotations.Schema;

namespace testef {
    //Model
    public partial class Case {
        public Case() {                
            Communications = new List<CaseCommunication>();
        }
        public Int32 Id { get; set; }

        public virtual ICollection<CaseCommunication> Communications { get; set; }
    }

    public class CaseCommunication  {

        public String CComType { get; set; }
        public Int32 Id { get; set; }

        public virtual Case Case { get; set; }

        public virtual User FirstReadBy { get; set; }
    }

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

    //Configuration for CObj
    public class UserEFCFConfiguration : EntityTypeConfiguration<User> {
        public UserEFCFConfiguration()
            : base() {
            ToTable("Users", "dbo");
            HasKey(x => x.Id);
            Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }

    public class CaseEFCFConfiguration : EntityTypeConfiguration<Case> {
        public CaseEFCFConfiguration()
            : base() {
            ToTable("Cases", "dbo");
            HasKey(x => x.Id);
            Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);   
        }
    }

    public class CaseCommunicationEFCFConfiguration : EntityTypeConfiguration<CaseCommunication> {
        public CaseCommunicationEFCFConfiguration()
            : base() {
            ToTable("VCaseCommunications", "dbo");
            Property(x => x.CComType).HasColumnType("char").HasMaxLength(2);

            HasKey(x => new { x.CComType, x.Id });

            // OK
            HasRequired(x => x.Case).WithMany(x => x.Communications).Map(x => x.MapKey("Case_Id"));
            HasOptional(x => x.FirstReadBy).WithMany().Map(x => x.MapKey("FirstReadBy_Id"));

            // KO
            //HasRequired(x => x.Case).WithMany(x => x.Communications);
            //HasOptional(x => x.FirstReadBy).WithMany()
            //EF tries to use the x.Id as FK for both Case and FirstReadBy
            //For FirstReadBy this leads to a Model error as x.Id is not nullable
            //But in each case I can't understand how EF expect to give the many relation by using a part of the PK as FK

            // OK
            //HasKey(x => x.Id);
            //HasRequired(x => x.Case).WithMany(x => x.Communications);
            //HasOptional(x => x.FirstReadBy).WithMany()
        }
    }

    public class TestEFContext : DbContext {
        public IDbSet<Case> Cases { get; set; }

        public TestEFContext(String cs)
            : base(cs) {
            Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
        }

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

            modelBuilder.Configurations.Add(new UserEFCFConfiguration());
            modelBuilder.Configurations.Add(new CaseEFCFConfiguration());
            modelBuilder.Configurations.Add(new CaseCommunicationEFCFConfiguration());
        }
    }

    class Program {
        static void Main(String[] args) {
            String cs = @"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";                

            using (TestEFContext c = new TestEFContext(cs)) {
                Console.WriteLine(c.Cases.Count());
            }                                                                
        }
    }
}

1 个答案:

答案 0 :(得分:0)

实际上这似乎是EF的默认行为:如果链接实体键的一部分与引用的实体PK具有相同的名称,则此命名属性将用作FK。