将现有数据汇总到新创建的记录中

时间:2014-08-04 08:08:49

标签: c# asp.net-mvc linq entity-framework sql-server-2008-r2

我在SQL方面经验丰富,在LINQ和OOP方面经验不足,结果对LINQ感到非常沮丧,所以请耐心等待。

我正在按照下面的标签使用MVC / Entity Framework。

我有两张桌子。一个名为Header的表绑定到网格。当我创建一个记录 要插入到此Header表中,我需要查找一些匹配的相关Detail记录并汇总并在网格中显示它们。

我现在将此限制在LINQ方面。

例如,我有这些详细记录:

Date         Segment    Location    Amount1   Amount2
2013-12-01   ABC        ZZ          12        2
2013-12-02   ABC        ZZ          50        3
2013-12-03   ABC        ZZ          2         4
2013-12-01   DEF        ZZ          7         5

我在网格中创建了这个标题记录:

DateFrom     DateTo        Segment    Location   DetailAmount1   DetailAmount2
2013-12-01   2013-12-07    ABC        ZZ         (      to be populated      )

DetailAmount1应为64,DetailAmount2应为9

所以我的视图调用控制器中的Grid_Create操作来获取一个带有所需数据的视图模型(除了我的汇总详细信息值和数据库生成的密钥之外什么都没有)

这是我的控制者:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Grid_Create(
        [DataSourceRequest]DataSourceRequest request,
        [Bind(Prefix = "models")]IEnumerable<Header_ViewModel> objects,
        string Location, 
        int? Segment_ID, 
        DateTime? Start_Date, 
        DateTime? End_Date)
    {
        using (var MyDB = new DBEntities())
        {
            // Keep the inserted entitites here. 
            // Used to return the result later.
            var entities = new List<Header_Table>();

            if (ModelState.IsValid)
            {
                foreach (var obj in objects)
                {
                    // PART A: Summarise estimates out of Detail
                    var est =
                        (from e in MyDB.Detail_Table
                         where e.SRC_System == Location
                         where e.Segment_ID == Segment_ID
                         where e.Transaction_Date >= Start_Date
                         where e.Transaction_Date <= End_Date
                         group e by e.Segment_ID into e
                         select
                         new Header_ViewModel
                         {
                             Amount1 = e.Sum(x => x.Amount1),
                             Amount2 = e.Sum(x => x.Amount2),
                             Amount3 = e.Sum(x => x.Amount3),
                             Amount4 = e.Sum(x => x.Amount4),
                             Amount5 = e.Sum(x => x.Amount5),
                             Amount6 = e.Sum(x => x.Amount6)
                         })
                         .FirstOrDefault();

                    // PART B: If there are no estimates, generate a 0
                    if (est == null)
                    {
                        est = new Header_ViewModel
                         {
                             Amount1 = 0,
                             Amount2 = 0,
                             Amount3 = 0,
                             Amount4 = 0,
                             Amount5 = 0,
                             Amount6 = 0
                         };
                    }

                    // PART C: Create a new entity 
                    // and set its properties from the posted model

                    var entity = new Header_Table
                    {
                        Transaction_ID = obj.Transaction_ID,
                        Value1 = obj.Value1,
                        Value2 = obj.Value2,
                        Value3 = obj.Value3,
                        // Summary from detail table
                        Amount2 = est.Amount2,//   obj.Amount2,
                        Amount3 = est.Amount3, // obj.Amount3,
                        Amount1 = est.Amount1,// obj.Amount1,
                        Amount4 = est.Amount4, //obj.Amount4,
                        Amount5 = est.Amount5, // obj.Amount5,
                        Amount6 = est.Amount6, //  obj.Amount6,
                        Location = Location,
                        Segment_ID = Segment_ID,
                        Start_Date = Start_Date,
                        End_Date = End_Date,
                        // assign default values
                        Updated_By = User.Identity.Name,
                        Updated_Date = DateTime.Now
                    };

                    // Add the entity
                    MyDB.Header_Table.Add(entity);
                    // Store the entity for later use
                    entities.Add(entity);
                }
                // Insert the entities in the database
                MyDB.SaveChanges();
            }
            // Return the inserted entities. Also return any validation errors.
            return Json(
                  entities.ToDataSourceResult(
                          request, 
                          ModelState, obj => new Header_ViewModel
            {
                Transaction_ID = obj.Transaction_ID,
                Amount2 = obj.Amount2,
                Value1 = obj.Value1,
                Amount3 = obj.Amount3,
                Amount1 = obj.Amount1
            }));
        }
    }

问题:

  1. 找不到详细记录。什么是将est对象默认为单个零项的好方法?目前在 B部分中我正在检查est==null并手动加载它。如何让FirstOrDefault自动为我做这个? (因此删除 B部分)。我相信我应该能够传入一个类型,但是我无法使语法正确,即如果我从B部分的new中获取所有内容并将其作为参数放入FirstOrDefault我得到System.Linq.IQueryable<Header_ViewModel> does not contain a definition for 'FirstOrDefault...

  2. A部分中获取摘要时,我实际上不需要按Segment_ID分组,我只需要该表的总摘要。然而,似乎我必须分组以获得LINQ中的聚合。我看过e.GetType()提及小组的其他帖子,但我收到错误LINQ to Entities does not recognize the method 'System.Type GetType()'.....

  3. 鉴于这是一条新记录,我是否可以直接从entity填充MyDB.Detail_Table(从而合并A和C部分)?我试过这个,但每次都有错误。抱歉没有发布确切的错误,但如果有人认为有可能我会再次尝试并发布错误。

1 个答案:

答案 0 :(得分:0)

问题1 我能想到的最简单的解决方案是(使用您的代码作为基础):

var est =
  (from e in MyDB.Detail_Table
   where e.SRC_System == Location
   where e.Segment_ID == Segment_ID
   where e.Transaction_Date >= Start_Date
   where e.Transaction_Date <= End_Date
   group e by e.Segment_ID into e
   select
   new Header_ViewModel
   {
       Amount1 = e.Sum(x => x.Amount1),
       Amount2 = e.Sum(x => x.Amount2),
       Amount3 = e.Sum(x => x.Amount3),
       Amount4 = e.Sum(x => x.Amount4),
       Amount5 = e.Sum(x => x.Amount5),
       Amount6 = e.Sum(x => x.Amount6)
   })
   .FirstOrDefault() ?? new Header_ViewModel();

问题2 嗯,是的......在这里做的不多,使用常数是可能的,如here所述。这似乎有效:

var est =
    MyDB.DetailTableSet.Where(e => e.SRC_System == Location && e.Segment_ID == Segment_ID 
        && e.Transaction_Date >= Start_Date && e.Transaction_Date <= End_Date)
        .GroupBy(e => 1)
        .Select(e => new Header_ViewModel
        {
            Amount1 = e.Sum(x => x.Amount1),
            Amount2 = e.Sum(x => x.Amount2),
        })
        .SingleOrDefault() ?? new Header_ViewModel();

问题3 没有好办法做到这一点。解释原因和一些解决方法here,但在你的情况下,我不会走得那么远。这就是我要去的地方:

var est =
    MyDB.DetailTableSet.Where(e => e.SRC_System == Location && e.Segment_ID == Segment_ID 
        && e.Transaction_Date >= Start_Date && e.Transaction_Date <= End_Date)
        .GroupBy(e => 1)
        .Select(e => new Header_ViewModel
        {
            Amount1 = e.Sum(x => x.Amount1),
            Amount2 = e.Sum(x => x.Amount2),
        })
        .SingleOrDefault() ?? new Header_ViewModel();

var entity = new HeaderTable()
{
    Transaction_ID = obj.Transaction_ID,
    Value1 = obj.Value1,
    Value2 = obj.Value2,
    Value3 = obj.Value3,
    // Summary from detail table
    Amount1 = est.Amount1,
    Amount2 = est.Amount2,
    Location = Location,
    Segment_ID = Segment_ID,
    Start_Date = Start_Date,
    End_Date = End_Date,
    // assign default values
    Updated_By = "Myself",
    Updated_Date = DateTime.Now
};


// Add the entity
MyDB.HeaderTableSet.Add(entity);
// Store the entity for later use
entities.Add(entity);