C# 如何使用EF填充我的基础客户

C# 如何使用EF填充我的基础客户,c#,entity-framework,linq,C#,Entity Framework,Linq,先看我的班级结构 public class CustomerBase { public int CustomerID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } pu

先看我的班级结构

public class CustomerBase
{
    public int CustomerID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string Address1 { get; set; }
    public string Address2 { get; set; }

    public string Phone { get; set; }
    public string Fax { get; set; }

}

public class Customer : CustomerBase
{
    public virtual List<Addresses> Addresses { get; set; }
}

public class Addresses
{
    [Key]
    public int AddressID { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public bool IsDefault { get; set; }
    public virtual List<Contacts> Contacts { get; set; }

    public int CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
}

public class Contacts
{
    [Key]
    public int ContactID { get; set; }

    public string Phone { get; set; }
    public string Fax { get; set; }
    public bool IsDefault { get; set; }

    public int AddressID { get; set; }
    public virtual Addresses Customer { get; set; } 

}

public class TestDBContext : DbContext
{
    public TestDBContext()
        : base("name=TestDBContext")
    {
    }

    public DbSet<Customer> Customer { get; set; }
    public DbSet<Addresses> Addresses { get; set; }
    public DbSet<Contacts> Contacts { get; set; }
}
根据我的情况,单个客户可能有多个地址,但应该有一个默认地址,我正在提取。一个地址可能有多个联系人的详细信息,但应该有一个默认的我拉


address1、address2、电话和传真属于基本客户类别。我想根据isdefault从地址和联系人表中提取单个数据,并填充我的客户。我的linq不太好。因此无法组合查询。请帮我作曲。谢谢

请尝试下面的代码,我想它可能适合您的要求

 var bsCustomer1 = db.Customer.Where(p => p.CustomerID == 2)
        .Select(x => new CustomerBase
        {
            CustomerID = x.CustomerID,
            FirstName = x.FirstName,
            LastName = x.LastName,
            Address1 = x.Addresses.First(a => a.IsDefault).Address1,
            Address2 = x.Addresses.First(a => a.IsDefault).Address2,
            Phone = x.Addresses.First(a => a.IsDefault).Contacts.First(c => c.IsDefault).Phone),
            Fax = x.Addresses.First(a => a.IsDefault).Contacts.First(c => c.IsDefault).Fax)
        }).ToList();

尝试下面的代码,猜测它可能适合您的请求

 var bsCustomer1 = db.Customer.Where(p => p.CustomerID == 2)
        .Select(x => new CustomerBase
        {
            CustomerID = x.CustomerID,
            FirstName = x.FirstName,
            LastName = x.LastName,
            Address1 = x.Addresses.First(a => a.IsDefault).Address1,
            Address2 = x.Addresses.First(a => a.IsDefault).Address2,
            Phone = x.Addresses.First(a => a.IsDefault).Contacts.First(c => c.IsDefault).Phone),
            Fax = x.Addresses.First(a => a.IsDefault).Contacts.First(c => c.IsDefault).Fax)
        }).ToList();

当您说:“我想根据isdefault从address和contacts表中提取单个数据并填充我的客户”时,不知道您的实际意思,这可能意味着两件事:

  • 我想投射一个新对象
  • 我想更新备份数据库
  • 好的,关于EF的一些事情:

  • 在数据库中有CRUD(创建、检索、更新、删除)语句的上下文
  • 设置EF文件时,上下文知道您在数据库中标识的所有对象
  • t4模板是为实体上下文和实体名称本身创建的,并在前面的步骤中生成上下文引用以及创建POCO类对象
  • 要创建新对象,不必参照其上方或下方的对象。您只需要创建它,然后用它更新数据库

    以EF为例,假设我有两个数据库表:

    我有一个表tePerson,其中包含字段:PersonId、FirstName、LastName、OrderId。此表包含值

    1   Brett   X 1
    2   Emily   X 2
    4   Ryan    Y 1
    10  Mark    Z 1 
    
    OrderId是表的外键,该表只有两个字段:OrderId和Description

    1   Shirt
    2   Dress
    
    从T4生成的我的POCO对象是:

    public partial class tePerson
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Nullable<int> OrderId { get; set; }
    
        public virtual teOrder teOrder { get; set; }
    }
    
    公共部分类
    {
    公共int PersonId{get;set;}
    公共字符串名{get;set;}
    公共字符串LastName{get;set;}
    公共可为空的OrderId{get;set;}
    公共虚拟teOrder teOrder{get;set;}
    }
    
    需要注意的是,“虚拟teOrder”指向我的另一个POCO,如下所示:

    public partial class teOrder
    {
        public teOrder()
        {
            this.tePersons = new HashSet<tePerson>();
        }
    
        public int OrderId { get; set; }
        public string Description { get; set; }
    
        public virtual ICollection<tePerson> tePersons { get; set; }
    }
    
    公共偏序类
    {
    公共秩序()
    {
    this.tePersons=newhashset();
    }
    公共int-OrderId{get;set;}
    公共字符串说明{get;set;}
    公共虚拟ICollection tePersons{get;set;}
    }
    
    示例,用于从上下文中投影和更新数据库,以及更新下面的数据库。要记住的关键一点是,在使用EF进行“选择”时,只有使用“ToList()”这样的方法使对象具体化,对象才能实现。否则,它们是无法链接的上下文数据库集

    public class OtherPerson
    {
      public int PersonId { get; set; }
      public string PersonLongName { get; set; }
      public teOrder Order { get; set; }
    }
    
    static void Main(string[] args)
    {
      using (var context = new TesterEntities())
      {
        //Say I just want to project a new object with a select starting from orders and then traversing up.  Not too hard
        var newObjects = context.teOrders.Where(order => order.OrderId == 1)
          //SelectMan will FLATTEN a list off of a parent or child in a one to many relationship
          .SelectMany(peopleInOrderOne => peopleInOrderOne.tePersons)
          .ToList()
          .Select(existingPerson => new OtherPerson
          {
            PersonId = existingPerson.PersonId,
            PersonLongName = $"{existingPerson.FirstName} {existingPerson.LastName}",
            Order = existingPerson.teOrder
          })
          .ToList();
    
        newObjects.ForEach(newPerson => Console.WriteLine($"{newPerson.PersonId} {newPerson.PersonLongName} {newPerson.Order.Description}"));
    
        // Just an action clause to repeat find items in my context, the important thing to note is that y extends teOrder which is another POCO inside my POCO
        Action<string, List<tePerson>> GetOrdersForPeople = (header, people) => 
        {
          Console.WriteLine(header);
          people.ForEach(person => Console.WriteLine($"{person.FirstName} {person.LastName} {person.teOrder.Description}"));
          Console.WriteLine();
        };
    
        //I want to look at a person and their orders.  I don't have to do multiple selects down, lazy loading by default gives me a child object off of EF
        GetOrdersForPeople("First Run", context.tePersons.ToList());
    
    
        //Say I want a new order for a set of persons in my list?
        var newOrder = new teOrder { Description = "Shoes" };
        context.teOrders.Add(newOrder);
        context.SaveChanges();
    
        //Now I want to add the new order
        context.tePersons.SingleOrDefault(person => person.PersonId == 1).teOrder = newOrder;
        context.SaveChanges();
    
        //I want to rexamine now
        GetOrdersForPeople("After changes", context.tePersons.ToList());
    
        //My newOrder is in memory and I can alter it like clay still and the database will know if I change the context
        newOrder.Description = "Athletic Shoes";
        context.SaveChanges();
    
        GetOrdersForPeople("After changes 2", context.tePersons.ToList());
    
        //Say I want to update a few people with new orders at the same time
        var peopleBesidesFirst = context.tePersons.Where(person => person.PersonId != 1).ToList();
        var firstPersonInList = context.tePersons.Where(person => person.PersonId == 1).ToList();
    
        var newOrders = new List<teOrder> {
          new teOrder { Description = "Hat", tePersons = peopleBesidesFirst },
          new teOrder { Description = "Tie", tePersons = firstPersonInList }
          };
    
        context.teOrders.AddRange(newOrders);
        context.SaveChanges();
    
        GetOrdersForPeople("After changes 3", context.tePersons.ToList());
      }
    
      Console.ReadLine();
    }
    
    公共类其他人
    {
    公共int PersonId{get;set;}
    公共字符串PersonLongName{get;set;}
    公共秩序{get;set;}
    }
    静态void Main(字符串[]参数)
    {
    使用(var context=newtesterentities())
    {
    //假设我只想用一个select从orders开始,然后向上遍历来投影一个新对象。不太难
    var newObjects=context.teOrders.Where(order=>order.OrderId==1)
    //SelectMan会将一对多关系中的父项或子项列表展平
    .SelectMany(peopleInOrderOne=>peopleInOrderOne.tePersons)
    托利斯先生()
    .选择(existingPerson=>new OtherPerson
    {
    PersonId=现有Person.PersonId,
    PersonLongName=$“{existingPerson.FirstName}{existingPerson.LastName}”,
    订单=existingPerson.teOrder
    })
    .ToList();
    newObjects.ForEach(newPerson=>Console.WriteLine($“{newPerson.PersonId}{newPerson.PersonLongName}{newPerson.Order.Description}”);
    //只是一个在我的上下文中重复find items的action子句,需要注意的是y扩展了teOrder,这是我的POCO中的另一个POCO
    Action GetOrdersForPeople=(标题,人物)=>
    {
    控制台写入线(标题);
    people.ForEach(person=>Console.WriteLine($“{person.FirstName}{person.LastName}{person.teOrder.Description}”);
    Console.WriteLine();
    };
    //我想看看一个人和他们的订单。我不需要做多次向下选择,默认情况下,延迟加载会给我一个子对象
    GetOrdersForPeople(“第一次运行”,context.tePersons.ToList());
    //假设我想为我名单上的一组人下一个新订单?
    var newOrder=new teOrder{Description=“Shoes”};
    context.teOrders.Add(newOrder);
    SaveChanges();
    //现在我想添加新订单
    context.tePersons.SingleOrDefault(person=>person.PersonId==1).teOrder=newOrder;
    SaveChanges();
    //我想现在就去
    GetOrdersForPeople(“更改后”,context.tePersons.ToList());
    //我的新订单在内存中,我可以像粘土一样修改它,如果我更改了上下文,数据库就会知道
    newOrder.Description=“运动鞋”;
    SaveChanges();
    GetOrdersForPeople(“更改后2”,context.tePersons.ToList());
    //假设我想同时用新订单更新几个人
    var peopleBesidesFirst=context.tePersons.Where(person=>person.PersonId!=1.ToList();
    var firstPersonInList=context.tePersons.Where(person=>person.PersonId==1.ToList();
    var newOrders=新列表{
    新的teOrder{Description=“Hat”,tePersons=peopleBesidesFirst},
    新命令{Description=“Tie”,tePersons=firstPersonInList}
    };
    context.teOrders.AddRange(newOrders);
    SaveChanges();
    GetOrdersForPeople(“更改后3”,context.tePersons.ToList());
    }
    Console.ReadLine();
    }
    
    当您说:“我想根据isdefault从地址和联系人表中提取单个数据并填充我的客户”时,您并不知道您的实际意思