1

我首先是 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 的地址集合。

任何方向/帮助将不胜感激......谢谢。

4

1 回答 1

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.

于 2012-10-03T14:15:44.987 回答