【问题标题】:Entity Framework POCO: How to map related properties to a flattened table?实体框架 POCO:如何将相关属性映射到扁平表?
【发布时间】:2012-07-11 14:27:28
【问题描述】:

我正在针对 SQL Server 2012 数据库使用实体框架(版本 4.3.1)POCO,并且我有这个数据架构...

Table2
======    
Table2Id : int : Identity (1,1) Primary Key not null
Name : nvarchar(10) not null

Table1
======    
Table1Id : int : Identity (1,1) Primary Key not null
Name : nvarchar(10) not null
Table2Id : int not null (foreign key to Table2)

Root
====
RootId : int : Identity (1,1) Primary Key not null
Table1Id : int not null (foreign key to Table1)
Table2Id : int not null (foreign key to Table2)

没有什么不好的除了现在有趣的是,我不想在我的 Root 对象上为 Table2 设置一个属性,而是希望从 Table1 的相关 Table2 中填充该 ID。

为了解释我的意思,这里是我的对象和上下文:

public class Root
{
    public int RootId { get; set; }
    public Table1 Table1 { get; set; }
}

public class Table1
{
    public int Table1Id { get; set; }
    public string Name { get; set; }
    public Table2 Table2 { get; set; }
    public virtual ICollection<Root> Roots { get; set; }
}

public class Table2
{
    public int Table2Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Table1> Table1s { get;set; }
}

public class Context : DbContext
{
    public Context(string nameOrConnectionString) 
        : base(nameOrConnectionString)
    {
        Roots = Set<Root>();
        Table1s = Set<Table1>();
        Table2s = Set<Table2>();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {          
        var table1 = modelBuilder.Entity<Table1>();
        table1.ToTable("Table1");
        table1.HasKey(r => r.Table1Id);
        table1.HasRequired(r => r.Table2)
            .WithMany(t => t.Table1s)
            .Map(m => m.MapKey("Table2Id"));

        var table2 = modelBuilder.Entity<Table2>();
        table2.ToTable("Table2");
        table2.HasKey(r => r.Table2Id);

        var root = modelBuilder.Entity<Root>();
        root.ToTable("Root");
        root.HasKey(r => r.RootId);
        root.HasRequired(r => r.Table1)
            .WithMany(t => t.Roots)
            .Map(m => m.MapKey("Table1Id"));

        // TODO: Some sort of mapping            

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Root> Roots { get; private set; }
    public DbSet<Table1> Table1s { get; private set; }
    public DbSet<Table2> Table2s{ get; private set; }
}

最终我想运行这段 sn-p 代码(在空数据库上)...

using(var c = new Context(@"connection string"))
{
    c.Roots.Add(new Root
    {
        Table1 = new Table1
        {
            Name = "Test1",
            Table2 = new Table2 { Name = "Test2" }
        }
    });
    c.SaveChanges();
}

然后数据看起来像这样:

Table2
======
Table2Id |  Name
       1 | Test2

Table1
=======
Table1Id |  Name
       1 | Test1

Root
====
RootId | Table1Id | Table2Id
1      |        1 |        1

那么,我该如何执行这样的映射?我查看了 Map 函数和 Property 函数,但我无法理解我应该将什么放在合适的位置或者即使它们合适? p>

【问题讨论】:

  • 你能写更多关于你想要达到的目标吗?要解决什么问题?

标签: c# .net poco entity-framework-4.3


【解决方案1】:

我不想要 Table2 的根对象上的属性,而是想要 从 Table1 中的相关 Table2 填充该 ID。

EF 不支持这个。您不能将关系中的属性值转发到主表。您必须在Table2Root 上公开导航属性,并以与Table1 相同的方式对其进行映射。

【讨论】:

  • 谢谢。如果我放一个 public int Table2Id { get;放; } 在 Root 上 - 我能以某种方式使用匹配属性 Table1.Table2.Table2Id 自动设置它吗?
【解决方案2】:

感谢@Ladislav Mrnka 指出它不受支持并且我需要一个导航属性,我决定我可以拥有一个私有导航属性,该属性遵循 Table1.Table2 属性并隐藏 ickyness。所以...

我像这样在我的 Root 类上定义了一个 private 导航属性(注意它不存储任何内容,只是遵循 Table1.Table2 属性):

public class Root
{
    public int RootId { get; set; }
    public Table1 Table1 { get; set; }
    private Table2 Table2
    {
        get { return Table1.Table2; }
        set { Table1.Table2 = value; }
    }
}

来自问题:Entity Framework 4 - Mapping non-public properties with CTP5 (code first) in a persistence unaware context 我创建了这个小助手(这只是意味着我可以获得私有属性的 lambda 表达式):

public interface IObjectExpressionCreator<T>
{
    Expression<Func<T, TResult>> Property<TResult>(string name);
}

public static class PropertyExpression
{
    private class ObjectExpressionCreator<T> : IObjectExpressionCreator<T>
    {
        public Expression<Func<T, TResult>> Property<TResult>(string name)
        {
            var p = Expression.Parameter(typeof(T),
                                         "propertyOrFieldContainer");

            var body = Expression.PropertyOrField(p, name);

            var lambda = Expression.Lambda(typeof(Func<T, TResult>),
                                           body,
                                           p);

            return (Expression<Func<T, TResult>>)lambda;
        }
    }
    public static IObjectExpressionCreator<T> For<T>()
    {
        return new ObjectExpressionCreator<T>();
    }
}

现在我像这样执行映射:

root
    .HasRequired(PropertyExpression.For<Root>().Property<Table2>("Table2"))
    .WithMany()
    .Map(m => m.MapKey("Table2Id"));

当我运行问题中的代码时,我得到的正是我想要的。

【讨论】:

    猜你喜欢
    • 2012-09-29
    • 2011-05-06
    • 1970-01-01
    • 2016-03-18
    • 2015-01-22
    • 2017-09-20
    • 2012-05-23
    • 2016-04-08
    • 1970-01-01
    相关资源
    最近更新 更多