简体   繁体   English

将 2 个表映射到实体框架中的单个实体

[英]Mapping 2 tables to single entity in Entity Framework

I hope you can help me.我希望你能帮助我。

I have 2 tables in the db: Bill and BillItem.我在数据库中有 2 个表:Bill 和 BillItem。 These tables are configured with one to one relation in the db where bill is the principle table while BillItem is the dependent one这些表在数据库中配置为一对一关系,其中 bill 是主表,而 BillItem 是依赖表

The structure of table Bill :表 Bill 的结构:

Int BillId (PK)
Int BillTypeId Not Null
Varchar(5) Usr Not Null
DateTime Tm Not Null

The structure of table BillItem:表 BillItem 的结构:

Int BillItemId (PK)
Int ItemId Not Null 
Varchar(5) Usr Not Null
DateTime Tm Not Null

I would like to map these 2 table into a single POCO class using Fluent API and Entity Framework 4.1 Code First approach我想使用 Fluent API 和 Entity Framework 4.1 Code First 方法将这两个表映射到单个 POCO 类中

I also want to configure the tables columns names to use different properties names in the POCO Class (ie Id instead of BillId, User instead of Usr)我还想配置表列名称以在 POCO 类中使用不同的属性名称(即 Id 而不是 BillId,User 而不是 Usr)

This is a legacy database, I cannot modify any of its objects.这是一个遗留数据库,我无法修改它的任何对象。

How can achieve that?怎样才能做到这一点?

Thank you all.谢谢你们。

The resulting class should be (if can be):结果类应该是(如果可以的话):

public int Id {get;set;}
public int BillTypeId {get;set;}
public int ItemId {get;set;}
public string User {get;set;}
public string User1 {get;set;}
public DateTime Tm {get;set;}
public DateTime Tm1 {get;set;}

For renaming columns, that's easy:对于重命名列,这很容易:

[Table("SomeHorribleTableName")]
    public class MyNiceTableName
    {
        [Column("Usr")]
        public string User { get; set; }
    }

Here I've renamed the entity as well.. no need to keep a horrible table name.在这里,我也重命名了实体。无需保留可怕的表名。 About the mapping 2 tables to 1 entity.. I don't think that's possible.关于将 2 个表映射到 1 个实体。我认为这是不可能的。 see here: Mapping data from 2 tables to 1 entity - Entity Framework 4请参阅此处: 将数据从 2 个表映射到 1 个实体 - 实体框架 4

Fluid style:流线型:

public class Bill
    {
        public int ID { get; set; }
        public int BillTypeID { get; set; }
        public string UserName { get; set; }
        public DateTime Time { get; set; }
    }

    public class BillItem
    {
        public int ID { get; set; }
        public int ItemID { get; set; }
        public string UserName { get; set; }
        public DateTime Time { get; set; }
    }

    internal class BillMap : EntityTypeConfiguration<Bill>
    {
        public BillMap()
        {
            ToTable("Bills");
            HasKey(x => x.ID);
            Property(x => x.ID).HasColumnName("BillId");
            Property(x => x.BillTypeID).IsRequired().HasColumnName("BillTypeId");
            Property(p => p.UserName).IsRequired().HasColumnName("Usr");
            Property(x => x.Time).IsRequired().HasColumnName("Tm");
        }
    }

    internal class BillItemMap : EntityTypeConfiguration<BillItem>
    {
        public BillItemMap()
        {
            ToTable("BillItems");
            HasKey(x => x.ID);
            Property(x => x.ID).HasColumnName("BillItemId");
            Property(x => x.ItemID).IsRequired().HasColumnName("ItemId");
            Property(p => p.UserName).IsRequired().HasColumnName("Usr");
            Property(x => x.Time).IsRequired().HasColumnName("Tm");
        }
    }

That's probably the best I can do.这可能是我能做的最好的了。 As for handling the Usr column in both tables, that'll be something you should probably deal with in your own controller classes / business logic layer.至于处理两个表中的 Usr 列,这可能是您应该在自己的控制器类/业务逻辑层中处理的事情。

One more thing: For the configuration classes above.. call them in your DbContext like so:还有一件事:对于上面的配置类.. 在您的 DbContext 中调用它们,如下所示:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new BillMap());
    modelBuilder.Configurations.Add(new BillItemMap());
}

I think you can achieve that with the Entity Splitting feature but you will need to use some Data Annotations (no esacpe):我认为您可以使用实体拆分功能来实现这一点,但您需要使用一些数据注释(无 esacpe):
WARNING : I HAVEN'T TRIED THIS METHOD BUT IT MIGHT WORK, CHECK IT OUT IF YOU LIKE First: Annotate the properties that belong to the BillItem table in you single domain model class with the HasColumnName data annotation.警告我还没有尝试过这种方法,但它可能会起作用,如果您喜欢,请检查一下首先:使用HasColumnName数据注释对属于您的单域模型类中的 BillItem 表的属性进行注释。
Second: Use this code sample第二:使用此代码示例

public class YourSingleModelClassNameConfiguration : EntityTypeConfiguration<YourSingleModelClassName> {
    public YourSingleModelClassNameConfiguration() {

        ToTable("Bill"); Property(param => param.Id).IsRequired().HasColumnName("BillId");

        // NOW REPEAT THAT FOR ALL BILL PROPERTIES WITH YOUR REQUIRED ATTRIBUTES (ISREQUIRED OR NOT, LENGTH ...)

        // NOW THE PROPERTIES YOU NEED TO MAP TO THE BILL ITEMS TABLE GOES INTO THE MAP FUNCTION
        Map(
        param =>
            { param.Properties(d => new {d.ItemId, d.User1}); m.ToTable("BillItem");
            }
        );

        // DON'T FORGET TO MENTION THE REST OF THE PROPERTIES BELONGING TO THE BillItem TABLE INSIDE THE PROPERTIES METHOD IN THE LAST LINE.

    }
}

for this question you can do it very easily and you got 2 options.对于这个问题,你可以很容易地做到这一点,你有 2 个选择。 The first is to map the classes using entity framework ( mapping multiple tables to a single entity class in entity framework ).第一种是使用实体框架映射类(将多个表映射到实体框架中的单个实体类)。

the second option is to do it manually: The restriction the 2 tables must follow is that 1 has to be the strong table and the second needs to be weak one (by doing this, you should have 1 by one only from the strong table to the weak) otherwise, this wont work as the result will be a collection of objects and then you will need to decide whether if the first object is the one that you need and no other.第二种选择是手动进行: 2 个表必须遵循的限制是 1 必须是强表,而第二个必须是弱表(通过这样做,您应该只有从强表到弱)否则,这将不起作用,因为结果将是对象的集合,然后您需要确定第一个对象是否是您需要的对象,而不是其他对象。

if you want to use a slightly faster approach i reccomend using your own logic to map the POCO objects.如果您想使用稍微快一点的方法,我建议您使用自己的逻辑来映射 POCO 对象。 create 2 clases that will map with the database table and from a service object build the object.创建 2 个将与数据库表映射并从服务对象构建对象的类。

this approach is good because the resulting LINQ query wont use INNER JOINS which makes it faster.这种方法很好,因为生成的 LINQ 查询不会使用 INNER JOINS,这使得它更快。 but the join should be kept from your side.但加入应该从你身边保持。

Example例子

int i=0;
// this 2 refer to the 2 different mapped tables in your context database
var pbdata = _pbdata.GetSingle(p=>p.StrongTableID == StrongTableID);
var pb = _pb.GetSingle(p=>p.WeakTableID == pbdata.WeakTableID);
// you can see that i am looking for the StrongTableID in order to select the entity value

// this is optional but usefull! you can do the
// "copy" inside a function where in future if the 
// object changes, you can update easily
ObjectComposite.Map(body, ref pb, ref pbdata);

// the following proccess needs to be done like this...
// first save the value in the weak object so 
// the WeakTableID is recorded
// UPDATE: maybe these 2 should go into a transact for more security... but... ok...
Save(pb);
i += this.unitOfWork.Save();
pbdata.ProfessionalBodyID = pb.ProfessionalBodyID;

// once the values for the second objects are set, save it all again.
Save(pbdata);
i += this.unitOfWork.Save();
return i > 0 ? true : false;

This approach is faster but you need to control everything from yourself.这种方法更快,但您需要自己控制一切。 the good thing is that here you can map as many tables as you want好消息是,您可以在这里映射任意数量的表格

hope it helps!希望能帮助到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM