3

我需要对客户执行联接。其中地址是主要的并填充 PrimaryAddress1 和 PrimaryCity 字段。客户映射已经与地址类有很多关系,但我不想获取所有地址(性能问题)。

请帮忙..

类:

public class Customer
{
    public Customer()
    {
        Addressess = new List<Address>();
    }
   public virtual int CustomerID { get; set; }
    public virtual int? BranchID { get; set; }
    public virtual int? CustTypeID { get; set; }
    public virtual string CompanyName { get; set; }
    public virtual string Prefix { get; set; }
    public virtual string FirstName { get; set; }
    public virtual string MiddleName { get; set; }
    public virtual string LastName { get; set; }
    public virtual string PrimaryAddress1 { get; set; }
    public virtual string PrimaryCity { get; set; }
    public virtual List<Address> Addresses { get; set; }
}


public class Address
{
    public Address()
    {
    }
    public virtual int LocationID { get; set; }
    public virtual int? CustomerID { get; set; }
    public virtual string LocationName { get; set; }
    public virtual string Address1 { get; set; }
    public virtual string Address2 { get; set; }
    public virtual string Address3 { get; set; }
    public virtual string City { get; set; }
    public virtual bool Primary { get; set; }
}

映射:

public TblCustomerMap()
{
    Table("tblCustomers");
    LazyLoad();
    Id(x => x.CustomerID).GeneratedBy.Identity().Column("CustomerID");
    Map(x => x.ProfileID).Column("ProfileID");
    Map(x => x.BranchID).Column("BranchID");
    Map(x => x.DateEntered).Column("DateEntered");
    Map(x => x.DateTerminated).Column("DateTerminated");
    Map(x => x.CustTypeID).Column("CustTypeID");
    Map(x => x.CompanyName).Column("CompanyName").Not.Nullable().Length(50);
    Map(x => x.Prefix).Column("Prefix").Not.Nullable().Length(50);
    Map(x => x.FirstName).Column("FirstName").Not.Nullable().Length(50);
    Map(x => x.MiddleName).Column("MiddleName").Not.Nullable().Length(50);
    Map(x => x.LastName).Column("LastName").Not.Nullable().Length(50);
    HasMany(x => x.Address).KeyColumn("CustomerID");
    Map(x => x.PrimaryAddress1).Column("PrimaryAddress1") // from table tbladdress where address is primary and get data from address1 column
    Map(x => x.PrimaryCity).Column("PrimaryCity") // from table tbladdress where address is primary and get data from city column
}

询问:

 var query = session
            .QueryOver<Customer>(() => customer)
            .JoinQueryOver(() => customer.Addresses, () => address)
            .Where(() => address.Primary)
            .List();

        foreach (var customer1 in query)
        {
            customer1.PrimaryAddress1 = customer1.Addresses[0].Address1;
            customer1.PrimaryCity = customer1.Addresses[0].City;
            customer1.PrimaryState = customer1.Addresses[0].StateOrProvince;

        }

新查询:

  var query = session.Query<Customer>()
            .SelectMany(c => c.Addresses,
                        (c, a) => new {c, a})
            .Where(cust => cust.a.Primary)
            .Select(item => new CustomerView()
                              {
                                 CustomerID = item.c.CustomerID,
                                 CompanyName=  item.c.CompanyName,
                                 FirstName=  item.c.FirstName,
                                  LastName=item.c.LastName,
                                  Address1=item.a.Address1,
                                  Address2=item.a.Address2,
                                 Address3= item.a.Address3,
                                 City= item.a.City,
                                 StateOrProvince= item.a.StateOrProvince
                              });
        return query.ToList();
4

2 回答 2

3

有(至少)两种方法可以实现这一点。

1)更直观易读的是扩展DB和调整NHibernate映射。我们将需要创建新视图 viewPrimaryAddress

SELECT ***columns*** FROM [tbladdress] WHERE Primary = true

客户映射将如下所示:

Join("[viewPrimaryAddress]", 
{
  m.Fetch.Join();
  m.KeyColumn("CustomerID");
  m.Map(t => t.PrimaryAddress1).Column("PrimaryAddress1");
  m.Map(t => t.PrimaryCity).Column("PrimaryCity");
});

就是这样。将发出一条 SQL 语句,因此无需加载地址集合

2) 第二种方法的概述

第二种方法将通过新的类映射创建该视图,有点复杂,但只能在应用程序端(C# 和 NHiberante)完成。

PrimaryAddress将创建新类并在类级别定义上包含过滤器(xml 映射示例:

<class name="PrimaryAddress" ... where="Primary = true" >

然后我们可以将Customer的多对一关系扩展到PrimaryAddress。因此,获取列“PrimaryAddress1”和“PrimaryCity”的属性将通过在 WHERE 子句中过滤的 SQL 选择来完成。

扩展:

下一步应指导您如何创建新映射,将主地址定位为一对一属性 1) C# PrimaryAddress:

public class PrimaryAddress
{
    public virtual Customer Customer { get; set; }
    public virtual string Address { get; set; }
    public virtual string City { get; set; }
}

2)映射:

public TblPrimaryAddressMap()
{
    Table("tbladdress");
    LazyLoad();
    Where("Primary = 1");
    // Id as AddressId
    References(x => x.Customer).Column("CustomerID");
    Map(x => x.Address).Column("PrimaryAddress1")
    Map(x => x.PrimaryCity).Column("PrimaryCity")
}

3) 新物业Customer

public class Customer
{  
   ..
   public virtual PrimaryAddress PrimaryAddress { get; set; }

4) Customer public TblCustomerMap() { ... HasOne(x => x.PrimaryAddress)的新映射

此时,当您Customer从会话中获取时。您可以访问

customer.PrimaryAddress.Address
customer.PrimaryAddress.City

我主要使用 XML 映射。但是从这些方面来看,这个概念应该很清楚......玩一些fetch="join"你可以加载的东西Customer,它PrimaryAddress在一个 SQL 选择中

如果您甚至需要客户属性Customer.PrimaryAddress1,只需将 PrimaryAddress.Address 包装在 getter 中即可。

您将获得更多,可以通过这个新属性进行过滤和排序PrimaryAddress

注意:这种方法对于缓存来说是脆弱的。原因是,虽然您将更改真实Address实体,但没有建立驱逐 的机制PrimaryAddress。此外,您应该强制业务层仅允许将一个地址设置为 primary = true 的客户

于 2012-11-23T05:55:09.743 回答
2

我有一个类似的地址结构并为此苦苦挣扎。一个主要问题是确保在客户没有主要地址的情况下返回客户记录(不应该发生,但是......)。

如果您想在 Customer 实体中包含地址字段,请查看连接映射。

我的方法是使用数据传输对象(DTO 或视图),在本例中为 CompanyDto:

    internal static QueryOver<Company> GetCompanyDtoQuery()
    {
        Address addr = null;
        CompanyDto dto = null;

        var query = QueryOver.Of<Company>()
            .Left.JoinAlias(c => c.Addresses, () => addr)
            .SelectList(list =>
                        {
                            list.Select(c => c.CompanyId).WithAlias(() => dto.CompanyId)
                            list.Select(a -> addr.AddressId).WithAlias(() => dto.AddressId
                            return list;
                        })
            .Where(a => addr.AddressId == null || addr.IsPrimaryAddress)
            .TransformUsing(new AliasToDtoDeepTransformer<CompanyDto>("PrimaryAddress"));
        return query;
    }

[编辑]

使用 Query 更容易做到这一点,例如:

            var target = (from c in session.Query<Company>()
                          from a in c.Addresses
                          where a.IsPrimaryAddress
                          select new
                              {
                                  c.CompanyId,
                                  a.Address1
                              })
                .Take(10).ToList();
            Assert.IsTrue(target.Any());

您发布的查询的问题是您通过按索引访问集合来强制延迟加载。您可以使用预先加载来一次选择获取所有地址:

             var target = session.QueryOver<Company>()
                                 .Fetch(c => c.Addresses).Eager
                                 .Take(10).List();
             Assert.IsTrue(target.Any());

但是,正如我在原始回复中所说,您应该查看 join 或其他方法,而不是在域模型中包含来自另一个表的字段。

于 2012-11-23T14:03:23.823 回答