0

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

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

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

1 回答 1

0

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

于 2013-04-24T09:23:54.867 回答