.net - mvc - update linq c# list
Se necesita ayuda para operaciones de LINQ a SQL(insertar/actualizar) con POCO anidados (5)
Bien, he estado tratando de convertir mi modelo para usar LINQ, pero no quería tirar mis DTO actuales y sus interfaces que están dispersas por el dominio.
Me las arreglé para encontrar esta publicación de blog que ha descrito el proceso bastante bien:
He logrado recuperar los registros de los objetos que funcionan correctamente, sin embargo, debido a la naturaleza anidada de mi modelo, parece que no puedo trabajar más con los objetos secundarios. Es decir, si creo un objeto hijo y establezco la referencia al objeto primario deseado, LINQ to SQL aún arroja una excepción que indica que la referencia del hijo al padre es nula. Si intento agregar un objeto principal antiguo simple, tiene éxito, pero no se pueden agregar objetos secundarios directamente.
Aquí está mi prueba de falla:
[Test]
public void AddSelectionShouldAddSelectionToMarket()
{
Market market = (Market) new Repository().GetMarket(1);
Selection selection = new Selection();
selection.Market = market;
new Repository().AddSelection(selection);
Assert.IsTrue(selection.SID > 0);
}
Aquí está el mensaje de error:
System.InvalidOperationException: se intentó eliminar una relación entre Market y Selection. Sin embargo, una de las claves externas de la relación (Selection.MID) no se puede establecer en nulo.
Las partes relevantes de los 2 objetos:
[DataContract]
public class Selection : ISelection
{
private int mID;
[DataMember]
public int MID
{
get { return this.mID; }
set { this.mID = value; }
}
private Market market;
[DataMember]
public Market Market
{
get { return this.market; }
set
{
this.market = value;
this.mID = value.MID;
}
}
}
[DataContract]
public class Market : IMarket
{
private int mID;
[DataMember]
public int MID
{
get { return this.mID; }
protected set { this.mID = value; }
}
private List<Selection> selections;
[DataMember]
public List<Selection> Selections
{
get { return this.selections; }
set
{
this.selections = value;
// For LINQ
foreach (Selection selection in selections)
{
selection.MID = mID;
selection.Market = this;
}
}
}
}
Mi código DA:
MarketsDataContext context = new MarketsDataContext();
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Selection>(s => s.Prices);
options.LoadWith<Market>(m => m.Selections);
context.LoadOptions = options;
return context;
y;
public void AddSelection(ISelection selection)
{
using (MarketsDataContext context = MarketsDataContext.GetContext())
{
context.Selections.InsertOnSubmit((Selection) selection);
context.SubmitChanges();
}
}
Y finalmente mi mapeo XML:
<Table Name="dbo.Markets" Member="Markets">
<Type Name="Market">
<Column Name="MID" Member="MID" Storage="mID" DbType="Int NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
<Association Name="FK_Market-Selections" Member="Selections" Storage="selections" ThisKey="MID" OtherKey="MID" DeleteRule="NO ACTION" />
</Type>
</Table>
<Table Name="dbo.Selections" Member="Selections">
<Type Name="Selection">
<Column Name="SID" Member="SID" Storage="sID" DbType="Int NOT NULL" IsPrimaryKey="true" IsDbGenerated="true" AutoSync="OnInsert" />
<Column Name="MID" Member="MID" Storage="mID" DbType="Int NOT NULL" />
<Association Name="FK_Market-Selections" Member="Market" Storage="market" ThisKey="MID" OtherKey="MID" IsForeignKey="true" />
</Type>
</Table>
Entonces, ¿alguien puede señalarme en la dirección correcta? He estado buscando por horas ...
Editar:
Aquí está mi stacktrace para mi falla de prueba:
at System.Data.Linq.ChangeTracker.StandardChangeTracker.StandardTrackedObject.SynchDependentData()
at System.Data.Linq.ChangeProcessor.ValidateAll(IEnumerable`1 list)
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at BetMax.DataModel.Repository.AddSelection(ISelection selection) in Repository.cs: line 68
at BetMax.DataModel.Test.ModelTest.AddSelectionShouldAddSelectionToMarket() in ModelTest.cs: line 65
Y mi método GetMarket:
public IMarket GetMarket(int MID)
{
Market market;
using (MarketsDataContext context = MarketsDataContext.GetContext())
{
market = context.Markets.Single(m => m.MID == MID);
}
return market;
}
Editar 2:
Bueno, agregando
DeleteOnNull="true"
a Selecciones clave externa en la asignación XML ha eliminado el error de clave externa, pero ahora obtengo una referencia nula en uno de los objetos secundarios de Selecciones, diciendo que su referencia a Selección es nula aunque la Selección se está inicializando sin establecer ninguna de sus variables (fuera de las claves foráneas). Incluso intenté crear un objeto hijo y establecí sus referencias correctamente, pero sigo recibiendo este error:
System.NullReferenceException: Object reference not set to an instance of an object.
at BetMax.DTO.Price.set_Selection(Selection value) in Price.cs: line 25
at System.Data.Linq.Mapping.PropertyAccessor.Accessor`3.SetValue(ref T instance, V value)
at System.Data.Linq.Mapping.MetaAccessor`2.SetBoxedValue(ref Object instance, Object value)
at System.Data.Linq.ChangeProcessor.ClearForeignKeysHelper(MetaAssociation assoc, Object trackedInstance)
at System.Data.Linq.ChangeProcessor.ClearForeignKeyReferences(TrackedObject to)
at System.Data.Linq.ChangeProcessor.PostProcessUpdates(List`1 insertedItems, List`1 deletedItems)
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at BetMax.DataModel.Repository.AddSelection(ISelection selection) in Repository.cs: line 68
at BetMax.DataModel.Test.ModelTest.AddSelectionShouldAddSelectionToMarket() in ModelTest.cs: line 69
El precio es otro objeto, construido de la misma manera que esa Selección se relaciona con el Mercado (1 selección tiene muchos precios, 1 mercado tiene muchas selecciones) etc. etc.
Para su nuevo problema; El problema ocurre en la asignación nula a la propiedad de selección de Price. ¿Lo hiciste con tu código? ¿Podrías darle otra vez al código que obtuviste la excepción? Me refiero a la asignación a la entidad Price ...
Edite según el comentario: supongo que es debido a la excepción de control nulo como mencionamos anteriormente en la publicación de GeekyMonkeys. En la inicialización de la clase Selection, la propiedad Price debe establecerse como null, pero cuando se asigna null, arroja una referencia nula. Entonces tiene que hacer un control nulo en el conjunto de propiedades de precio.
private List<Price> prices
[DataMember]
public List<Price> Prices
{
get { return this.prices; }
set
{
if(value != null)
{
this.pricess = value;
// For LINQ
foreach (Price price in prices)
{
price.MID = mID;
price.Selection = this;
}
}
}
}
Solo una conjetura, pero podría estar aquí
public Market Market
{
get { return this.market; }
set
{
this.market = value;
this.mID = value.MID;
}
}
¿Qué sucede cuando el valor que estableces en Market es nulo? La última línea de eso será inválida ya que no podrá resolver null.MID. Quizás necesites esto para tu setter:
set
{
this.market = value;
this.mID = (value == null) ? null : value.MID;
}
También tu MID debería ser nulo
int? MID
Sugiero que envíes tu código a Sidar Ok. Es un buen tipo y te guiará en la dirección correcta. O al menos publicar un comentario en su blog que lo indique a su pregunta aquí.
Supongo que el problema está en tu método de prueba. Creaste un Repositorio con un DataContext pero hiciste tus envíos con otro.
[Test]
public void AddSelectionShouldAddSelectionToMarket()
{
Market market = (Market) new Repository().GetMarket(1);
Selection selection = new Selection();
selection.Market = market;
new Repository().AddSelection(selection);
Assert.IsTrue(selection.SID > 0);
}
Crea un repositorio y úsalo en el método de prueba.
[Test]
public void AddSelectionShouldAddSelectionToMarket()
{
Repository repository = new Repository();
Market market = (Market) repository.GetMarket(1);
Selection selection = new Selection();
selection.Market = market;
repository.AddSelection(selection);
Assert.IsTrue(selection.SID > 0);
}
Sé que ha pasado un tiempo y probablemente ya hayas resuelto el problema, pero tal vez no ...
Supongo que su estructura de datos es similar a esto:
Market
======
Market_ID int not null identity (1, 1)
Selection
=========
Selection_ID int not null identity (1, 1)
Market_ID int (FK to Market)
Selection_Name varchar(50)
Para agregar un nuevo Mercado y una nueva Selección simultáneamente:
Selection selection = new Selection();
Market market = new Market();
market.Selections.Add(selection);
DataContext.Markets.InsertOnSubmit(market);
DataContext.SubmitChanges();
Para agregar una nueva selección a un mercado existente:
Selection selection = new Selection();
Market market = DataContext.Markets.Where(a => a.Market_ID == 7).Single();
market.Selections.Add(selection);
DataContext.SubmitChanges();
Para actualizar la primera selección en un mercado:
Selection selection = DataContext.Markets.Where(a => a.Market_ID == 7).Selections.First();
selection.Selection_Name = "New Name";
DataContext.SubmitChanges();