实体框架6.1:在子对象CRUD [英] Entity Framework 6.1: CRUD on Child objects

查看:211
本文介绍了实体框架6.1:在子对象CRUD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我填充与来自这样的资源库对象列表的数据网格:

 公共静态的IEnumerable<排序> GetOrdersForDataGrid()
    {
        IEnumerable的<排序>查询;
        使用(RSDContext =新RSDContext())
        {
            查询= context.Orders.Include(O => o.OrderDetails).ToList();
        }
        返回查询;
    }

当我想编辑我选定行传递到一个新的窗口像这样的命令:

  OrderEditWindow orderEdit =新OrderEditWindow();
        orderEdit.SelectedOrder = SelectedOrder;
        orderEdit.ShowDialog();

下面我将在DataContext的窗口为:

 的DataContext = SelectedOrder;

在此窗口中我有一个结合订单订单明细集合属性另一个数据网格。问题是,在CRUD操作上订单明细。例如,在我添加了一个新的OrderDetail是这样的:

 私人无效AddProductDetailButton_OnClick(对象发件人,RoutedEventArgs E)
    {
        如果(!ValidateProductDetail())
            返回;
        VAR _selectedProduct = ProductAutoCompleteBox.SelectedItem的产品;
        VAR selectedProduct = ProductsRepository.GetProductById(_se​​lectedProduct.ProductId);
        的OrderDetail的OrderDetail =新的OrderDetail();
        orderDetail.Price = selectedProduct.Price;
        。orderDetail.Product code = selectedProduct code;
        orderDetail.ProductName = selectedProduct.Name;
        orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
        orderDetail.Um = selectedProduct.Um;
        orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
        orderDetail.Group = selectedProduct.Subgroup.Group.Name;
        orderDetail.Subgroup = selectedProduct.Subgroup.Name;
        orderDetail.SupplierName = selectedProduct.Supplier.Name;
        //orderDetail.Order=SelectedOrder;
        //orderDetail.OrderId = SelectedOrder.OrderId;
        SelectedOrder.OrderDetails.Add(的OrderDetail);        ProductAutoCompleteBox.Text =的String.Empty;
        QuantityNumericUpDown.Value = 1;
        ProductAutoCompleteBox.Focus();    }

然后我从调用存储库的更新方法:

 公共静态无效UpdateOrder(订单顺序)
    {
        使用(RSDContext上下文=新RSDContext())
        {
            context.Orders.Attach(订单);
            context.Entry(顺序).STATE = EntityState.Modified;
            context.SaveChanges();
        }
    }

我得到的OrderId一个错误。如果我设置manualy导航属性和ID我没有得到一个错误,但变化不得到保存到数据库。

我的订单模式是这样的:

 公共类订单:INotifyPropertyChanged的
{
    公共事件PropertyChangedEventHandler的PropertyChanged;    公共秩序()
    {
        _OrderDetails =新的ObservableCollection<&的OrderDetail GT;();
        _OrderDetails.CollectionChanged + = _OrderDetails_CollectionChanged;
    }    无效_OrderDetails_CollectionChanged(对象发件人,System.Collections.Specialized.NotifyCollectionChangedEventArgs E)
    {
        如果(e.NewItems!= NULL)
            AttachProductChangedEventHandler(e.NewItems.Cast&所述;的OrderDetail>());
        如果(e.OldItems!= NULL)
            CalcualteTotals();
    }
    [NotMapped]
    公共小数CalculatedTotal
    {
        得到
        {
            返回OrderDetails.Sum(X => x.Total);
        }
    }
    公众诠释的OrderId {搞定;组; }    私人诠释_number;    公众诠释号码
    {
        {返回_number; }
        组
        {
            _number =价值;
            NotifyPropertyChanged(编号);
        }
    }    私人的DateTime _DATE;    公众的DateTime日期
    {
        {返回_DATE; }
        组
        {
            _DATE =价值;
            NotifyPropertyChanged(日期);
        }
    }    私人布尔_Canceled;    公共BOOL取消
    {
        {返回_Canceled; }
        组
        {
            _Canceled =价值;
            NotifyPropertyChanged(取消);
        }
    }
    私人字符串_ClientName;    公共字符串CLIENTNAME
    {
        {返回_ClientName; }
        组
        {
            _Cli​​entName =价值;
            NotifyPropertyChanged(CLIENTNAME);
        }
    }
    私人字符串_ClientPhone;    公共字符串ClientPhone
    {
        {返回_ClientPhone; }
        组
        {
            _Cli​​entPhone =价值;
            NotifyPropertyChanged(ClientPhone);
        }
    }    私人字符串_DeliveryAddress;    公共字符串DeliveryAddress
    {
        {返回_DeliveryAddress; }
        组
        {
            _DeliveryAddress =价值;
            NotifyPropertyChanged(DeliveryAddress);
        }
    }    私人小数_Transport;    公共运输小数
    {
        {返回_Transport; }
        组
        {
            _Transport =价值;
            NotifyPropertyChanged(运输);
        }
    }    私人小数_Total;    公共小数总
    {
        {返回_Total; }
        组
        {
            _Total =价值;
            NotifyPropertyChanged(合计);
        }
    }    私人的ObservableCollection<&的OrderDetail GT; _订单详细信息;    公共虚拟的ObservableCollection<&的OrderDetail GT;订单详细信息
    {
        // {返回_OrderDetails? (_OrderDetails =新的ObservableCollection<&的OrderDetail GT;()); }
        得到
        {
            返回_OrderDetails;
        }
        组
        {
            _OrderDetails =价值;
            NotifyPropertyChanged(订单明细);
        }
    }
    私人无效AttachProductChangedEventHandler(IEnumerable的<&的OrderDetail GT;订单明细)
    {        的foreach(在ORDERDETAILS VAR P)
        {
            p.PropertyChanged + =(发件人,E)=>
            {
                开关(e.PropertyName)
                {
                    案量:
                    案价:
                    案共:
                        CalcualteTotals();
                        打破;
                }
            };
        }        CalcualteTotals();
    }    公共无效CalcualteTotals()
    {
        NotifyPropertyChanged(CalculatedTotal);    }
    公共无效NotifyPropertyChanged(字符串propertyName的)
    {
        如果(的PropertyChanged!= NULL)
        {
            的PropertyChanged(这一点,
                新PropertyChangedEventArgs(propertyName的));
        }
    }
}

和我的OrderDetail模式是这样的:

 公共类的OrderDetail:INotifyPropertyChanged的
{
    公共事件PropertyChangedEventHandler的PropertyChanged;
    公众诠释OrderDetailId {搞定;组; }
    公众诠释的OrderId {搞定;组; }    治安秩序得到{;组; }    私人诠释_产品code;
    公众诠释产品code
    {
        得到{_产品code; }
        组
        {
            _产品code =价值;
            NotifyPropertyChanged(产品code);
        }
    }    私人字符串_ProductName;    公共字符串产品名称
    {
        {返回_ProductName; }
        组
        {
            _ProductName =价值;
            NotifyPropertyChanged(产品名称);
        }
    }    私人字符串_Um;    公共字符串庵
    {
        {返回_Um; }
        组
        {
            _Um =价值;
            NotifyPropertyChanged(嗯);
        }
    }    私人小数_Price;    公共小数价格
    {
        {返回_Price; }
        组
        {
            _Price =价值;
            NotifyPropertyChanged(价格);
            NotifyPropertyChanged(合计);        }
    }    私人诠释_Quantity;    公众诠释数量
    {
        {返回_Quantity; }
        组
        {
            _Quantity =价值;
            NotifyPropertyChanged(数量);
            NotifyPropertyChanged(合计);        }
    }    私人字符串_SupplierName;    公共字符串SupplierName
    {
        {返回_SupplierName; }
        组
        {
            _SupplierName =价值;
            NotifyPropertyChanged(SupplierName);
        }
    }    私人字符串_Subgroup;    公共字符串小组
    {
        {返回_Subgroup; }
        组
        {
            _Subgroup =价值;
            NotifyPropertyChanged(小组);
        }
    }    私人字符串_Group;    公共字符串集团
    {
        {返回_Group; }
        组
        {
            _Group =价值;
            NotifyPropertyChanged(「本集团」);
        }
    }    公共小数_Total;    公共小数总
    {
        {返回数量*价格; }
        组
        {
            _Total =价值;
            NotifyPropertyChanged(合计);
        }
    }    公共无效NotifyPropertyChanged(字符串propertyName的)
    {
        如果(的PropertyChanged!= NULL)
        {
            的PropertyChanged(这一点,
                新PropertyChangedEventArgs(propertyName的));
        }
    }
}

我真的想使用某种工作单位的,我不明白,我也应该对对象应用CRUD与子集合并保持在同一时间(更新UI通过在工作的ObservableCollection ,并使用绑定ClientPhone,模式=双向,UpdateSourceTrigger = PropertyChanged的我型我父窗口更新)

最后一个有效的解决方案:

 使用(RSDContext上下文=新RSDContext())
        {
            VAR细节= order.OrderDetails;
            order.OrderDetails = NULL;
            清单< INT> OriginalOrderDetailsIds =
             context.OrderDetails.Where(O => o.OrderId == order.OrderId)。选择(O = GT; o.OrderDetailId).ToList();
            清单< INT> CurrentOrderDetailsIds = details.Select(O => o.OrderDetailId).ToList();
            清单< INT> DeletedOrderDetailsIds = OriginalOrderDetailsIds.Except(CurrentOrderDetailsIds).ToList();            context.Entry(顺序).STATE = EntityState.Modified;
            的foreach(在DeletedOrderDetailsIds VAR deletedOrderDetailId)
            {
                context.Entry(context.OrderDetails.Single(O => o.OrderDetailId == deletedOrderDetailId))状态= EntityState.Deleted。
            }
            的foreach(详细的OrderDetail细节)
            {
                //添加。
                如果(detail.OrderDetailId == 0)
                {
                    detail.OrderId = order.OrderId;
                    context.Entry(细节).STATE = EntityState.Added;
                }
                //更新。
                其他
                {
                    context.Entry(细节).STATE = EntityState.Modified;
                }
            }
            context.SaveChanges();
        }


解决方案

您可以做这样的添加和更新的孩子,但不知道在UI删除的订单的详细信息。如果你不希望得到实体的顺序,你需要某种形式的标记的OrderDetail已删除的OrderDetail的。

 使用(RSDContext上下文=新RSDContext())
{
    VAR细节= order.OrderDetails;
    order.OrderDetails = NULL;    context.Entry(顺序).STATE = EntityState.Modified;
    的foreach(详细VAR细节)
    {
        如果(detail.Id == 0)
        {
            //添加。
            detail.OrderId = order.Id;
            context.Entry(细节).STATE = EntityState.Added;
        }
        否则,如果(detail.IsDeleted)
        //添加请将isDeleted所谓新特性
        //并添加[NotMapped]属性
        //然后标记这个属性为true从已删除项目的UI。
        {
           //删除。
           context.Entry(细节).STATE = EntityState.Deleted;
        }
        其他
        {
           // 更新。
           context.Entry(细节).STATE = EntityState.Modified;
        }
    }    order.OrderDetails =细节;
    context.SaveChanges();
}

I populate a data grid with a list of objects that come from a repository like this:

   public static IEnumerable<Order> GetOrdersForDataGrid()
    {
        IEnumerable<Order> query;
        using (RSDContext = new RSDContext())
        {
            query = context.Orders.Include(o=>o.OrderDetails).ToList();
        }
        return query;
    }

When I want to edit an order I pass the selected row to a new window like this:

 OrderEditWindow orderEdit = new OrderEditWindow();
        orderEdit.SelectedOrder = SelectedOrder;
        orderEdit.ShowDialog();

Here I set the DataContext of the Window to:

DataContext = SelectedOrder;

In this window I have another data grid that binds to OrderDetails collection property of Order. The problem is on CRUD operations on OrderDetails. For example, after I add a new orderDetail like this:

  private void AddProductDetailButton_OnClick(object sender, RoutedEventArgs e)
    {
        if (!ValidateProductDetail())
            return;
        var _selectedProduct = ProductAutoCompleteBox.SelectedItem as Product;
        var selectedProduct = ProductsRepository.GetProductById(_selectedProduct.ProductId);
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.Price = selectedProduct.Price;
        orderDetail.ProductCode = selectedProduct.Code;
        orderDetail.ProductName = selectedProduct.Name;
        orderDetail.Quantity = int.Parse(QuantityNumericUpDown.Value.ToString());
        orderDetail.Um = selectedProduct.Um;
        orderDetail.Total = selectedProduct.Price * int.Parse(QuantityNumericUpDown.Value.ToString());
        orderDetail.Group = selectedProduct.Subgroup.Group.Name;
        orderDetail.Subgroup = selectedProduct.Subgroup.Name;
        orderDetail.SupplierName = selectedProduct.Supplier.Name;
        //orderDetail.Order=SelectedOrder;
        //orderDetail.OrderId = SelectedOrder.OrderId;
        SelectedOrder.OrderDetails.Add(orderDetail);

        ProductAutoCompleteBox.Text = string.Empty;
        QuantityNumericUpDown.Value = 1;
        ProductAutoCompleteBox.Focus();

    }

and then I call the update method from repository:

  public static void UpdateOrder(Order order)
    {
        using (RSDContext context = new RSDContext())
        {
            context.Orders.Attach(order);
            context.Entry(order).State = EntityState.Modified;
            context.SaveChanges();
        }
    }

I get an error about OrderId. If i set manualy the navigation property and the id I don't get an error but changes dont get saved into db.

My Order model look like this:

 public  class Order : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Order()
    {
        _OrderDetails = new ObservableCollection<OrderDetail>();
        _OrderDetails.CollectionChanged += _OrderDetails_CollectionChanged;
    }

    void _OrderDetails_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
            AttachProductChangedEventHandler(e.NewItems.Cast<OrderDetail>());
        if (e.OldItems != null)
            CalcualteTotals();
    }
    [NotMapped]
    public decimal CalculatedTotal
    {
        get
        {
            return OrderDetails.Sum(x => x.Total);
        }
    }
    public int OrderId { get; set; }

    private int _Number;

    public int Number
    {
        get { return _Number; }
        set
        {
            _Number = value;
            NotifyPropertyChanged("Number");
        }
    }

    private DateTime _Date;

    public DateTime Date
    {
        get { return _Date; }
        set
        {
            _Date = value;
            NotifyPropertyChanged("Date");
        }
    }

    private bool _Canceled;

    public bool Canceled
    {
        get { return _Canceled; }
        set
        {
            _Canceled = value;
            NotifyPropertyChanged("Canceled");
        }
    }
    private string _ClientName;

    public string ClientName
    {
        get { return _ClientName; }
        set
        {
            _ClientName = value;
            NotifyPropertyChanged("ClientName");
        }
    }
    private string _ClientPhone;

    public string ClientPhone
    {
        get { return _ClientPhone; }
        set
        {
            _ClientPhone = value;
            NotifyPropertyChanged("ClientPhone");
        }
    }

    private string _DeliveryAddress;

    public string DeliveryAddress
    {
        get { return _DeliveryAddress; }
        set
        {
            _DeliveryAddress = value;
            NotifyPropertyChanged("DeliveryAddress");
        }
    }

    private decimal _Transport;

    public decimal Transport
    {
        get { return _Transport; }
        set
        {
            _Transport = value;
            NotifyPropertyChanged("Transport");
        }
    }

    private decimal _Total;

    public decimal Total
    {
        get { return _Total; }
        set
        {
            _Total = value;
            NotifyPropertyChanged("Total");
        }
    }



    private ObservableCollection<OrderDetail> _OrderDetails;

    public virtual ObservableCollection<OrderDetail> OrderDetails
    {
        //get { return _OrderDetails ?? (_OrderDetails = new ObservableCollection<OrderDetail>()); }
        get
        {
            return _OrderDetails;
        }
        set
        {
            _OrderDetails = value;
            NotifyPropertyChanged("OrderDetails");
        }
    }
    private void AttachProductChangedEventHandler(IEnumerable<OrderDetail> orderDetails)
    {

        foreach (var p in orderDetails)
        {
            p.PropertyChanged += (sender, e) =>
            {
                switch (e.PropertyName)
                {
                    case "Quantity":
                    case "Price":
                    case "Total":
                        CalcualteTotals();
                        break;
                }
            };
        }

        CalcualteTotals();
    }

    public void CalcualteTotals()
    {
        NotifyPropertyChanged("CalculatedTotal");

    }
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

And my OrderDetail model look like this:

 public class OrderDetail : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;


    public int OrderDetailId { get; set; }
    public int OrderId { get; set; }

    public Order Order { get; set; }

    private int _ProductCode;
    public int ProductCode
    {
        get { return _ProductCode; }
        set
        {
            _ProductCode = value;
            NotifyPropertyChanged("ProductCode");
        }
    }

    private string _ProductName;

    public string ProductName
    {
        get { return _ProductName; }
        set
        {
            _ProductName = value;
            NotifyPropertyChanged("ProductName");
        }
    }

    private string _Um;

    public string Um
    {
        get { return _Um; }
        set
        {
            _Um = value;
            NotifyPropertyChanged("Um");
        }
    }

    private decimal _Price;

    public decimal Price
    {
        get { return _Price; }
        set
        {
            _Price = value;
            NotifyPropertyChanged("Price");
            NotifyPropertyChanged("Total");

        }
    }

    private int _Quantity;

    public int Quantity
    {
        get { return _Quantity; }
        set
        {
            _Quantity = value;
            NotifyPropertyChanged("Quantity");
            NotifyPropertyChanged("Total");

        }
    }

    private string _SupplierName;

    public string SupplierName
    {
        get { return _SupplierName; }
        set
        {
            _SupplierName = value;
            NotifyPropertyChanged("SupplierName");
        }
    }

    private string _Subgroup;

    public string Subgroup
    {
        get { return _Subgroup; }
        set
        {
            _Subgroup = value;
            NotifyPropertyChanged("Subgroup");
        }
    }

    private string _Group;

    public string Group
    {
        get { return _Group; }
        set
        {
            _Group = value;
            NotifyPropertyChanged("Group");
        }
    }

    public decimal _Total;

    public decimal Total
    {
        get { return Quantity * Price; }
        set
        {
            _Total = value;
            NotifyPropertyChanged("Total");
        }
    }

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

I'm really trying to use some sort of unit of work and I don't understand how i'm supposed to apply CRUD on objects with child collections and keep the UI updated in the same time (by working in a ObservableCollection and using Binding ClientPhone, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged my parent window is updated as I type)

A final working solution:

   using (RSDContext context = new RSDContext())
        {
            var details = order.OrderDetails;
            order.OrderDetails = null;
            List<int> OriginalOrderDetailsIds =
             context.OrderDetails.Where(o => o.OrderId == order.OrderId).Select(o => o.OrderDetailId).ToList();
            List<int> CurrentOrderDetailsIds = details.Select(o => o.OrderDetailId).ToList();
            List<int> DeletedOrderDetailsIds = OriginalOrderDetailsIds.Except(CurrentOrderDetailsIds).ToList();

            context.Entry(order).State = EntityState.Modified;
            foreach (var deletedOrderDetailId in DeletedOrderDetailsIds)
            {
                context.Entry(context.OrderDetails.Single(o => o.OrderDetailId == deletedOrderDetailId)).State = EntityState.Deleted;
            }
            foreach (OrderDetail detail in details)
            {
                // Add.
                if (detail.OrderDetailId == 0)
                {
                    detail.OrderId = order.OrderId;
                    context.Entry(detail).State = EntityState.Added;
                }
                // Update.
                else
                {
                    context.Entry(detail).State = EntityState.Modified;
                }
            }
            context.SaveChanges();
        }

解决方案

You could do this way for adding and updating the child, but not sure about deleted order details in the ui. If you don't want to get the order from entity, you need some kind of marking in the OrderDetail for deleted OrderDetail.

using (RSDContext context = new RSDContext())
{
    var details = order.OrderDetails;
    order.OrderDetails = null;

    context.Entry(order).State = EntityState.Modified;
    foreach (var detail in details)
    {
        if (detail.Id == 0)
        {
            // Adds.
            detail.OrderId = order.Id;
            context.Entry(detail).State = EntityState.Added;
        }
        else if (detail.IsDeleted)
        // Adds new property called 'IsDeleted' 
        //  and add [NotMapped] attribute 
        //  then mark this property as true from the UI for deleted items.
        {
           // Deletes.
           context.Entry(detail).State = EntityState.Deleted;
        }
        else
        {
           // Updates.
           context.Entry(detail).State = EntityState.Modified;
        }
    }

    order.OrderDetails = details;
    context.SaveChanges();
}

这篇关于实体框架6.1:在子对象CRUD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆