【问题标题】:EF Code First and Linq to Entities, How to populate nested objects in one go?EF Code First 和 Linq to Entities,如何一次性填充嵌套对象?
【发布时间】:2013-04-12 06:36:47
【问题描述】:

我知道那里有类似的问题,这个几乎是一样的How to create and populate a nested ViewModel well,但它并没有解决我的问题。

我使用的是 EF Code First 和 LINQ to Entities。这些是我的一些实体

 public class Application
{
    public int ApplicationID { get; set; }
    public int ApplicationTypeID { get; set; }
    public int MembershipTypeID { get; set; }
    public string MailTo { get; set; }
    public DateTime ApplicationDate { get; set; }
    public int PersonID { get; set; }

    .......

    public virtual Person Person { get; set; }

    .......

    public virtual PaymentType PaymentType { get; set; }
}  


    public class Person
{
    public int PersonID { get; set; }
    public int? OrganisationID { get; set; }
    public int? HomeAddressID { get; set; }
    public int? WorkAddressID { get; set; }
    public string Title { get; set; }
    public string Initials { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public string JobTitle { get; set; }
    public string Department { get; set; }
    public string Phone { get; set; }
    public string Fax { get; set; }
    public string Email { get; set; }
    public bool NoInhouseMail { get; set; }
    public bool NoThirdPartyMail { get; set; }
    public DateTime Created { get; set; }
    public DateTime? Updated { get; set; }

    public virtual Address HomeAddress { get; set; }
    public virtual Address WorkAddress { get; set; }
    public virtual Organisation Organisation { get; set; }

    public virtual ICollection<PersonAttribute> PersonAttributes { get; set; }
    public virtual ICollection<Email> Emails { get; set; }
}

{
public class Address
{
    public int AddressID { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string Town { get; set; }
    public string Region { get; set; }
    public string Postcode { get; set; }
    public string CountryCode { get; set; }
    public DateTime Created { get; set; }
    public DateTime? Updated { get; set; }

    public virtual Country Country { get; set; }
}

这就是它们的映射方式

public ApplicationEntityTypeConfiguration()
    {
        //Mapping
        this.HasKey(ap => ap.ApplicationID);
        this.Property(ap => ap.ApplicationID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        this.Property(ap => ap.WorldPayID)
            .HasColumnType("bigint");

        this.Property(ap => ap.Processed)
            .HasColumnType("smalldatetime");

        this.Property(ap => ap.Exported)
            .HasColumnType("smalldatetime");

        //Relationships
        this.HasRequired(ap => ap.MembershipType)
            .WithMany()
            .HasForeignKey(ap => ap.MembershipTypeID);

        this.HasRequired(ap => ap.ApplicationType)
            .WithMany()
            .HasForeignKey(ap => ap.ApplicationTypeID);

        this.HasOptional(ap => ap.WorldPayStatus)
            .WithMany()
            .HasForeignKey(ap => ap.WorldPayStatusCode);

        this.HasRequired(ap => ap.PaymentType)
            .WithMany()
            .HasForeignKey(ap => ap.PaymentTypeID);

        this.HasRequired(ap => ap.Person)
            .WithMany()
            .HasForeignKey(ap => ap.PersonID);

        this.HasRequired(ap => ap.InvoiceAddress)
            .WithMany()
            .HasForeignKey(ap => ap.InvoiceAddressID);
    }
}

public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
    public PersonEntityTypeConfiguration()
    {
        this.HasKey(p => p.PersonID);
        this.Property(p => p.PersonID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        this.Property(p => p.Created)
            .HasColumnType("smalldatetime");

        this.Property(p => p.Updated)
            .HasColumnType("smalldatetime");

        //Relationships
        this.HasRequired(p => p.Organisation)
            .WithMany()
            .HasForeignKey(p => p.OrganisationID);

        this.HasRequired(p => p.HomeAddress)
            .WithMany()
            .HasForeignKey(p => p.HomeAddressID);

        this.HasRequired(p => p.WorkAddress)
            .WithMany()
            .HasForeignKey(p => p.WorkAddressID);
    }
}

public class AddressEntityTypeConfiguration : EntityTypeConfiguration<Address>
{

    public AddressEntityTypeConfiguration()
    {
        this.HasKey(a => a.AddressID);
        this.Property(a => a.AddressID)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        this.Property(a => a.Created)
            .HasColumnType("smalldatetime");

        this.Property(a => a.Updated)
            .HasColumnType("smalldatetime");

        //Relationships))))
        this.HasRequired(a => a.Country)
            .WithMany()
            .HasForeignKey(a => a.CountryCode)
            .WillCascadeOnDelete(false);

    }

}

这是我要填充的类的结构

public class OrganisationEmailMessageData
{
    public string ApplicationType { get; set; }
    public int ApplicationId { get; set; }
    public string PaymentType { get; set; }
    public string MembershipType { get; set; }
    public double Price { get; set; }
    public string FullName { get; set; }
    public string JobTitle { get; set; }
    public string Department { get; set; }
    public string Organisation { get; set; }
    public AddressEmailData HomeAddress { get; set; }
    public AddressEmailData WorkAddress { get; set; }
    public AddressEmailData InvoiceAddress { get; set; }
    public string PublicArea { get; set; }
    public string[] AreasOfInterest { get; set; }
}

public class AddressEmailData
{
    public bool Selected { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string Address3 { get; set; }
    public string Address4 { get; set; }
    public string Town { get; set; }
    public string Region { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
}

这是我尝试一次性填充 OrganisationEmailMessageData 类型的对象的方式,

 using (var db = _databaseFactory.GetDatabase())
        {
            var messageData = (from a in db.Applications
                           where a.ApplicationID == applicationId
                           select new OrganisationEmailMessageData
                                      {
                                        ApplicationType = a.ApplicationType.EmailMessage,
                                        ApplicationId = a.ApplicationID,
                                        PaymentType = a.PaymentType.Type,
                                        MembershipType = a.MembershipType.Type,
                                        Price = a.MembershipType.Price,
                                        FullName = a.Person.Title + " " + a.Person.Forename + " " + a.Person.Surname,
                                        JobTitle = a.Person.JobTitle,
                                        Department = a.Person.Department ?? string.Empty,
                                        Organisation = a.Person.Organisation != null
                                                            ? a.Person.Organisation.Name
                                                            : string.Empty,
                                        HomeAddress = a.Person.HomeAddressID.HasValue
                                                        ? ( from add in db.Addresses
                                                            where add.AddressID == a.Person.HomeAddressID.Value
                                                            select new AddressEmailData
                                                                        {
                                                                            Address1 = add.Address1,
                                                                            Address2 = add.Address2,
                                                                            Address3 = add.Address3,
                                                                            Address4 = add.Address4,
                                                                            Region = add.Region,
                                                                            Town = add.Town,
                                                                            PostalCode = add.Postcode,
                                                                            Country = add.Country.Name
                                                                        }).Single()
                                                        : null,
                                        WorkAddress = a.Person.WorkAddressID.HasValue
                                                        ? (from add in db.Addresses
                                                            where add.AddressID == a.Person.WorkAddressID.Value
                                                            select new AddressEmailData
                                                                        {
                                                                            Address1 = add.Address1,
                                                                            Address2 = add.Address2,
                                                                            Address3 = add.Address3,
                                                                            Address4 = add.Address4,
                                                                            Region = add.Region,
                                                                            Town = add.Town,
                                                                            PostalCode = add.Postcode,
                                                                            Country = add.Country.Name
                                                                        }).Single()
                                                        : null,
                                        InvoiceAddress = (from add in db.Addresses
                                                        where add.AddressID == a.InvoiceAddressID
                                                        select new AddressEmailData
                                                                    {
                                                                        Address1 = add.Address1,
                                                                        Address2 = add.Address2,
                                                                        Address3 = add.Address3,
                                                                        Address4 = add.Address4,
                                                                        Region = add.Region,
                                                                        Town = add.Town,
                                                                        PostalCode = add.Postcode,
                                                                        Country = add.Country.Name
                                                                    }).Single(),

                                        PublicArea = a.Person.PersonAttributes.Select(att => att.Attribute.Parent.Value).FirstOrDefault(),
                                        AreasOfInterest = a.Person.PersonAttributes.Select(att => att.Attribute.Value).ToArray()
                                      }
                         ).SingleOrDefault();

我以前在使用 LINQ to SQL 时在其他应用程序中这样做过,但是在运行应用程序时使用 LINQ to Entities 时出现此错误

Unable to create a constant value of type 'Namespace.Model.Entities.Address'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.

模型有什么问题吗?因为这是在抱怨地址实体。
我在顶部How to create and populate a nested ViewModel well 发布的问题的解决方案是删除嵌套集合的 ToList() 方法调用,但这不适用于 Single() 方法调用。
任何帮助都感激不尽。

【问题讨论】:

    标签: entity-framework-4 code-first


    【解决方案1】:

    问题在于您在同一 LINQ 查询中将 LINQ to Entities 与 LINQ to 对象混合在一起。我看到的最简单的解决方法是,您首先使用一个 LINQ 查询从数据库中获取结果,然后在第二个 LINQ 查询中将结果投影到所需的对象中。

    //LINQ TO Entities - DbQuery
    var dbResults = (from a in db.Applications
                           where a.ApplicationID == applicationId
                 select a).ToList();
    
    //LINQ To Objects-- project results from Db into required object
    var messageData = (from a in dbResults 
                    select new OrganisationEmailMessageData
                                      {
                                        ApplicationType = a.ApplicationType.EmailMessage,
                                        ApplicationId = a.ApplicationID,
                                        PaymentType = a.PaymentType.Type,
                                        MembershipType = a.MembershipType.Type,
                                        Price = a.MembershipType.Price,
                                        FullName = a.Person.Title + " " + a.Person.Forename + " " + a.Person.Surname,
                                        JobTitle = a.Person.JobTitle,
                                        Department = a.Person.Department ?? string.Empty,
                                        Organisation = a.Person.Organisation != null
                                                            ? a.Person.Organisation.Name
                                                            : string.Empty,
                                        HomeAddress = a.Person.HomeAddressID.HasValue
                                                        ? ( from add in db.Addresses
                                                            where add.AddressID == a.Person.HomeAddressID.Value
                                                            select new AddressEmailData
                                                                        {
                                                                            Address1 = add.Address1,
                                                                            Address2 = add.Address2,
                                                                            Address3 = add.Address3,
                                                                            Address4 = add.Address4,
                                                                            Region = add.Region,
                                                                            Town = add.Town,
                                                                            PostalCode = add.Postcode,
                                                                            Country = add.Country.Name
                                                                        }).Single()
                                                        : null,
                                        WorkAddress = a.Person.WorkAddressID.HasValue
                                                        ? (from add in db.Addresses
                                                            where add.AddressID == a.Person.WorkAddressID.Value
                                                            select new AddressEmailData
                                                                        {
                                                                            Address1 = add.Address1,
                                                                            Address2 = add.Address2,
                                                                            Address3 = add.Address3,
                                                                            Address4 = add.Address4,
                                                                            Region = add.Region,
                                                                            Town = add.Town,
                                                                            PostalCode = add.Postcode,
                                                                            Country = add.Country.Name
                                                                        }).Single()
                                                        : null,
                                        InvoiceAddress = (from add in db.Addresses
                                                        where add.AddressID == a.InvoiceAddressID
                                                        select new AddressEmailData
                                                                    {
                                                                        Address1 = add.Address1,
                                                                        Address2 = add.Address2,
                                                                        Address3 = add.Address3,
                                                                        Address4 = add.Address4,
                                                                        Region = add.Region,
                                                                        Town = add.Town,
                                                                        PostalCode = add.Postcode,
                                                                        Country = add.Country.Name
                                                                    }).Single(),
    
                                        PublicArea = a.Person.PersonAttributes.Select(att => att.Attribute.Parent.Value).FirstOrDefault(),
                                        AreasOfInterest = a.Person.PersonAttributes.Select(att => att.Attribute.Value).ToArray()
                                      }
                         ).SingleOrDefault();
    

    【讨论】:

    • 谢谢jure。我已将其用作解决方案,唯一我仍然不明白的是为什么这适用于 LINQ to SQL 而不是 EF 和 LINQ to 实体。
    猜你喜欢
    • 2011-08-29
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多