lambda的Linq更新问题

本文关键字:新问题 更新 Linq lambda | 更新日期: 2023-09-27 17:49:48

我正试图用lambda在Linq中编写一些代码。这是我使用lambda的第一个代码,我在更新记录时面临一个问题。我的代码是:

using (DataClasses1DataContext db = new DataClasses1DataContext())
{
    Table<NOTIF_RECIP> NOTIF_RECIP_alias = db.GetTable<NOTIF_RECIP>();
    Table<NOTIF_SCHED> NOTIF_SCHED_alias = db.GetTable<NOTIF_SCHED>();
    Table<mainframe_replication> mainframe_replication_alias = db.GetTable<mainframe_replication>();
    var ids = NOTIF_SCHED_alias.Select(x => x.NOTIF_RPT_ID).ToArray();

    foreach (string notif_sched_data in ids)
    {
        var repljoinmf = mainframe_replication_alias
                        .Join(NOTIF_RECIP_alias,
                             mfr => mfr.RPT_ID,
                             nr => nr.NOTIF_RECIP_ID,
                             (mfr, nr) => new
                             {
                                 ReportId=mfr.RPT_ID, 
                                 Reportversion=mfr.RPT_VERS,
                                 ReportBytes= mfr.RPT_BYTES.ToString(), 
                                 ReportDate=mfr.REPL_DTM.ToString(),
                                 NotifId= mfr.NOTIF_ID,
                                 RecipAdd=nr.NOTIF_RECIP_ADDR
                             });
        foreach(var repljoinmf_data in repljoinmf)
        {
            //DO STUFF 
            repljoinmf_data.NotifId = "Changedxyz";
            //db.SubmitChanges();
        }
    }
}

我在repljoinmf_data.NotifId = "Changedxyz";中得到错误错误提示:错误2属性或索引器"匿名类型#3"。NotifId'不能分配给——它是只读的

有谁能帮我一下吗?我认为这是因为我正在使用var,这是匿名的,但如何解决问题。如有任何帮助,不胜感激。

谢谢

lambda的Linq更新问题

正如错误提示的那样,匿名类实例一旦被投影就不能被修改。

虽然您可以切换到强类型类,然后重新分配成员属性,但是,您有机会将前面LINQ语句中期望的结果投影到相同的匿名类中:

var repljoinmf = mainframe_replication_alias
.Join(NOTIF_RECIP_alias, mfr => mfr.RPT_ID, nr => nr.NOTIF_RECIP_ID, 
(mfr, nr) => new // Anon Class projection
{ 
    ReportId=mfr.RPT_ID, 
    Reportversion=mfr.RPT_VERS,
    ReportBytes= mfr.RPT_BYTES.ToString(),     
    ReportDate=mfr.REPL_DTM.ToString(),
    NotifId= "Changedxyz", // *** No need to mutate this afterwards
    RecipAdd=nr.NOTIF_RECIP_ADDR 
});

编辑,更新不是琐碎的任务,建议替代

选项#1:在投影后具有突变的强类型类

添加一个新类(我已经猜到了一些类型)

public class MyPoco
{
     public int ReportId {get; set;}
     public string Reportversion {get; set;}
     public byte[] ReportBytes {get; set;}
     public DateTime ReportDate {get; set;}
     public int NotifId {get; set;}
     public string RecipAdd {get; set;}
}

然后您可以将其投影到(只需指定类名而不是匿名):

(mfr, nr) => new MyPoco // Not anonymous
{ 
    ReportId=mfr.RPT_ID, 
    ...

然后修改:

foreach(var repljoinmf_data in repljoinmf)
{
  repljoinmf_data.NotifId = "SomeNewValue"

选项#2 -创建一个方法(或Func)来执行复杂的逻辑

既然您似乎已经物化了所有数据,那么您可以自由地在属性投影中使用复杂函数。任何可用的局部变量(闭包)都可以传递给该函数,连接lambda参数(mfr, nr)

也是如此。

因此,例如,写一个函数来计算您的NotifId = "Changedxyz"替换:

private string DoIntensiveLogic(mainframe_replication mfr, NOTIF_RECIP nr)
{
    // Do Stuff
}

可以在原始匿名投影中使用:

(mfr, nr) => new // Anon Class projection
{ 
    ReportId=mfr.RPT_ID, 
    Reportversion=mfr.RPT_VERS,
    ReportBytes= mfr.RPT_BYTES.ToString(),     
    ReportDate=mfr.REPL_DTM.ToString(),
    NotifId= DoIntensiveLogic(mfr, nr), // Call the function each row
    RecipAdd=nr.NOTIF_RECIP_ADDR 
});

匿名类型是immutable,因此创建后不能更改,必须创建一个新类型
为了解决这个问题,你必须创建自己的类型,避免在将来需要更新时使用匿名类型。
你的字体可能看起来像这样

public class  ReportInfo
{
   public  int Id{get; set;} 
//the same thing  for others properties 
}

,你的查询将看起来像这样

new ReportInfo() { 
                Id = mfr.RPT_ID, 
                Reportversion = mfr.RPT_VERS,
                ReportBytes = mfr.RPT_BYTES.ToString(), 
                ReportDate = mfr.REPL_DTM.ToString(),
                NotifId = mfr.NOTIF_ID, 
                RecipAdd = nr.NOTIF_RECIP_ADDR 
            })

你可以很容易地更新你的属性

 foreach(var repljoinmf_data in repljoinmf)
        {
            //DO STUFF 
             repljoinmf_data.NotifId = "Changedxyz";
           //db.SubmitChanges();
        }

关于匿名类型的更多信息
编译器实际在做什么。当你写这样一行代码时:

var o = new { property1 = expression1, ..., propertyN = expressionN };

编译器推断每个表达式的类型,创建这些推断类型的私有字段,创建每个字段的公共只读属性,并创建一个接受所有这些属性的构造函数表达式。构造函数的代码从表达式结果初始化私有只读字段传递给它。此外,编译器会覆盖Object的Equals、GetHashCode和ToString

如果您想稍后更改' notfid ',您可以通过id找到记录并更改属性。

的例子:

var alias = mainframe_replication_alias.SingleOrDefault(mfr => mfr.NOTIF_ID == repljoinmf_data.NotifId);
if(alias != null)
   alias.NOTIF_ID = "Changedxyz";