2015-05-19 1 views
3

Я пытаюсь написать некоторый код в Linq с 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 Свойство или индексатор «AnonymousType # 3.NotifId» не может быть назначен - только

читается Может кто-то, пожалуйста, помогите мне в этом. Я думаю, что это потому, что я использую var, который является анонимным, но как решить проблему. Любая помощь приветствуется.

Благодаря

+4

'var' не _anonymous_, это просто означает "пусть компилятор решить, какой тип" –

+0

@DStanley Спасибо за разъяснение. – v2v2

ответ

1

Как следует ошибка, экземпляры анонимных классов не могут быть изменены, как только они были спроектированы.

Хотя вы могли бы перейти к сильному классу типизированного, а затем переназначить свойство элементов, однако, у вас есть возможность проецировать желаемый результат в предыдущем заявлении 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 
}); 

Edit, Update не тривиальное задание, предложил альтернативы

Вариант № 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), который делает сложную логику

Поскольку вы, кажется, уже материализовали все данные, вы можете использовать сложные функции в проекциях свойств. Любой из доступных локальных переменных (закрытий) можно перейти к такой функции, равно как и присоединиться к лямбде-параметрам (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 
}); 
+0

Спасибо, но мне нужно изменить значение Notifid каждый раз, основываясь на некоторых условиях. Я не хочу, чтобы он фиксировался как «Changedxyz». – v2v2

+0

Я обновил два способа достижения этого. Я бы предпочел второй вариант, так как он избегает нового класса, а также выполняет проекцию за один шаг. Изменение результата впоследствии обязательно всегда выглядит немного противно ИМО. – StuartLC

+0

Спасибо, Sir.you является спасателем жизни. Все работает сейчас, но когда вы звоните ** db.SubmitChanges() **, никаких изменений в базе данных. Я пропустил что-то еще? Еще раз спасибо – v2v2

1

анонимных типов являются 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 }; 

компилятор выводит тип каждого выражения, создает частные поля этих выведенных типов, создает публичные только для чтения свойства для каждого из полей, и создает конструктор, который принимает все эти выражения . Код конструктора инициализирует частные поля только для чтения из результатов выражения , переданных ему. Кроме того, компилятор переопределяет методы Equal, GetHashCode и ToString и генерирует код внутри всех этих методов.

+0

любое предложение .how? – v2v2

+0

Спасибо большое, сэр, но мой плохой может не отметить как ответ, поскольку возможен только один. – v2v2

0

Если вы хотите изменить «NotifId» позже, вы можете найти запись по id и изменить свойство.

Пример:

var alias = mainframe_replication_alias.SingleOrDefault(mfr => mfr.NOTIF_ID == repljoinmf_data.NotifId); 
if(alias != null) 
    alias.NOTIF_ID = "Changedxyz"; 
Смежные вопросы