如何修改这个Entity框架代码的第一个代码?

时间:2012-10-02 20:42:36

标签: entity-framework .net-4.0 ef-code-first

我首先是Entity Framework代码的新手,所以我们非常感谢任何帮助或方向。

我目前有以下课程:

public partial class Customer
{
    public int Id { get; set; }
    private ICollection<Address> _addresses;
}

public partial class Address
{
    public int Id { get; set; }
    public string Street { get; set; };
    public string City { get; set; };
    public string Zip { get; set; };
}

以及

public partial class CustomerMap : EntityTypeConfiguration<Customer>
{
    public CustomerMap()
    {
        this.ToTable("Customer");
        this.HasKey(c => c.Id);

        this.HasMany<Address>(c => c.Addresses)
            .WithMany()
            .Map(m => m.ToTable("CustomerAddresses"));
    }
}

这正如我所料,并为映射创建Customer,Address和CustomerAddresses表。现在我的问题..如果我需要修改代码以生成以下内容,我该怎么办...

我想将一个CompanyCode属性添加到“CustomerAddresses”表...然后而不是构建一组地址..我希望能够构造一个哈希表,其中键是CompanyCode,值是地址的集合。

所以,如果我有以下内容:

Customer
ID     C1

Address
ID     A1
ID     A2

CustomerAddresses
CustomerID      C1
AddressID     A1
CompanyCode    ABC

CustomerID      C1
AddressID     A2
CompanyCode    ABC

CustomerID      C1
AddressID     A2
CompanyCode    XYZ

然后,Customer.Addresses [“ABC”]将返回ID,A1和A2的地址集合。而Customer.Addresses [“XYZ”]将返回ID为A2的地址集合。

非常感谢任何方向/帮助......谢谢。

1 个答案:

答案 0 :(得分:1)

据我所知,不可能用索引器引入这样的导航属性。您的索引器实际上是一个查询,您必须将其表达为查询。我看到的唯一方法是按原样保留导航集合,并引入第二个(未映射)属性,该属性使用过滤器的导航集合。最大的缺点是这样的过滤器会在LINQ-to-Objects的内存中发生,并且要求您在过滤集合之前首先从数据库中加载完整的集合(例如,通过急切或延迟加载)。

我可能会将这样的过滤器留在实体本身之外,并在存储库或服务类中实现它,或者通常是从数据库加载实体的地方/模块。

您需要做的第一件事是将CustomerAddresses表作为模型中的实体公开,因为使用其他自定义属性CompanyCode,您不能再使用多对多关系,相反,你需要两个一对多的关系。新实体看起来像这样:

public partial class CustomerAddress
{
    public int CustomerId { get; set; }
    // public Customer Customer { get; set; } // optional

    public int AddressId { get; set; }
    public Address Address { get; set; }

    public string CompanyCode { get; set; }
}

Customer需要更改为:

public partial class Customer
{
    public int Id { get; set; }
    public ICollection<CustomerAddress> CustomerAddresses { get; set; }
}

您需要将映射更改为:

public CustomerMap()
{
    this.ToTable("Customer");
    this.HasKey(c => c.Id);

    this.HasMany(c => c.CustomerAddresses)
        .WithRequired() // or .WithRequired(ca => ca.Customer)
        .HasForeignKey(ca => ca.CustomerId);
}

为新实体创建新映射:

public CustomerAddressMap()
{
    this.ToTable("CustomerAddresses");
    this.HasKey(ca => new { ca.CustomerId, ca.AddressId, ca.CompanyCode });
    // or what is the PK on that table?
    // Maybe you need an Id property if this key isn't unique

    this.HasRequired(ca => ca.Address)
        .WithMany()
        .HasForeignKey(ca => ca.AddressId);
}

现在,在某些服务类中,您可以加载已过滤的地址:

public List<Address> GetAddresses(int customerId, string companyCode)
{
    return context.CustomerAddresses.Where(ca =>
        ca.CustomerId == customerId && ca.CompanyCode == companyCode)
        .ToList();
}

或者,如果您想要将客户与过滤后的地址一起加载:

public Customer GetCustomer(int customerId, string companyCode)
{
    var customer = context.Customer.SingleOrDefault(c => c.Id == customerId);
    if (customer != null)
        context.Entry(customer).Collection(c => c.CustomerAddresses).Query()
            .Where(ca => ca.CompanyCode == companyCode)
            .Load();
    return customer;
}

最后一个例子是两个数据库查询。

Customer实体中,您可以使用帮助属性来预测CustomerAddresses集合中的地址:

public partial class Customer
{
    public int Id { get; set; }
    public ICollection<CustomerAddress> CustomerAddresses { get; set; }

    public IEnumerable<Address> Addresses
    {
        get
        {
            if (CustomerAddresses != null)
                return CustomerAddresses.Select(ca => ca.Address);
            return null;
        }
    }
}

请记住,此属性不会查询数据库,结果依赖于已加载到CustomerAddresses的内容。