2014-10-06 11 views
6

Ich habe folgende entites/Tabellen:WP8 & Linq to SQL mit One-to-Many Beziehung: SubmitChanges() entfernt falsche Einheit

  • Board: Ein Board kann viele Pins haben
  • Pin: One Pin ist einer Karte zugeordnet. Diese Entität ist abstrakt und hat Childs mit verschiedenen Implementierungen. Alle Childs Zugehörigkeit zum Mutter Stift Einheit mit InheritanceMapping und wird in den Stift Tisch und zeichnet sich durch eine Discriminator column
    • TaskPin gespeichert werden: Dies ist ein Kind Implementierungen von Stift. Es kann viele Aufgaben haben.
  • Task: Eine Aufgabe ist mit einem TaskPin
zugewiesen

Hier einige Code ist meine Struktur klarer zu machen:

[Table] 
public class Board : ModelBase 
{ 
    private int _boardId; 

    [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity" 
         ,CanBeNull = false, AutoSync = AutoSync.OnInsert)] 
    public int BoardId 
    { 
     get { return _boardId; } 
     set { SetProperty(ref _boardId, value); } 
    } 

    private EntitySet<Pin> _pins; 

    [Association(Storage = "_pins", OtherKey = "_boardId" 
    ,ThisKey = "BoardId", DeleteRule = "CASCADE")] 
    public EntitySet<Pin> Pins 
    { 
     get { return _pins; } 
     set { _pins.Assign(value); } 
    } 

    public Board() 
    { 
     _pins = new EntitySet<Pin>(new Action<Pin>(this.addPin) 
      ,new Action<Pin>(this.removePin)); 
    } 

    private void addPin(Pin pin) 
    { 
     NotifyPropertyChanging("Pin"); 
     pin.Board = this; 
    } 

    private void removePin(Pin pin) 
    { 
     NotifyPropertyChanging("Pin"); 
     pin.Board = null; 
    } 
} 

[Table] 
[InheritanceMapping(Code = PinType.TaskPin, Type = typeof(TaskPin) 
      ,IsDefault = true)] 
public abstract class Pin : ModelBase 
{ 
    private int _pinId; 

    [Column(IsPrimaryKey = true, IsDbGenerated = true 
     ,DbType = "INT NOT NULL Identity", AutoSync = AutoSync.OnInsert)] 
    public int PinId 
    { 
     get { return _pinId; } 
     set { SetProperty(ref _pinId, value); } 
    } 

    [Column] 
    internal int _boardId; 

    private EntityRef<Board> _board; 

    [Association(Storage = "_board", ThisKey = "_boardId" 
     ,OtherKey = "BoardId", IsForeignKey = true, DeleteOnNull = true)] 
    public Board Board 
    { 
     get { return _board.Entity; } 
     set 
     { 
      if (SetProperty(ref _board, value) != null) 
      { 
       _boardId = value.BoardId; 
      } 
     } 
    } 

    [Column(IsDiscriminator = true)] 
    public PinType Type { get; set; } 


    public Pin() 
    { 

    } 
} 

public class TaskPin : Pin 
{ 
    private EntitySet<Task> _tasks; 

    [Association(Storage = "_tasks", OtherKey = "_pinId" 
     ,ThisKey = "PinId", DeleteRule = "CASCADE")] 
    public EntitySet<Task> Tasks 
    { 
     get { return _tasks; } 
     set { _tasks.Assign(value); } 
    } 

    public TaskPin() 
    { 
     _tasks = new EntitySet<Task>(new Action<Task>(this.addTask) 
       ,new Action<Task>(this.removeTask)); 
    } 

    private void addTask(Task task) 
    { 
     NotifyPropertyChanging("Task"); 
     task.Pin = this; 
    } 

    private void removeTask(Task task) 
    { 
     NotifyPropertyChanging("Task"); 
     task.Pin = null; 
    } 
} 

[Table] 
public class Task : ModelBase 
{ 
    private int _taskId; 

    [Column(IsPrimaryKey = true, IsDbGenerated = true 
         ,DbType = "INT NOT NULL Identity" 
         ,CanBeNull = false, AutoSync = AutoSync.OnInsert)] 
    public int TaskId 
    { 
     get { return _taskId; } 
     set { SetProperty(ref _taskId, value); } 
    } 

    [Column] 
    internal int _pinId; 

    private EntityRef<Pin> _pin; 

    [Association(Storage = "_pin", ThisKey = "_pinId" 
         ,OtherKey = "PinId" 
         ,IsForeignKey = true 
         ,DeleteOnNull=true)] 
    public Pin Pin 
    { 
     get { return _pin.Entity; } 
     set 
     { 
      if (SetProperty(ref _pin, value) != null) 
      { 
       _pinId = value.PinId; 
      } 
     } 
    } 

    public Task() 
    { 

    } 
} 

ich eine TaskPin und weisen Sie auf ein Brett. Dann erstelle ich zwei Aufgaben und ordne sie dem TaskPin zu. Das funktioniert gut. Das Problem occurrs wenn ich auf die einem oder mehr Tasks vom TaskPin versuchen:

private void OnDeleteTasks(object sender, EventArgs e) 
    { 
     TaskPin taskPin = pin as TaskPin; 
     var completedTasks = taskPin.Tasks 
          .Where(x => x.IsDone == true) 
          .ToList(); 

     foreach (var task in completedTasks) 
     { 
      taskPin.Tasks.Remove(task); 
     } 
    } 

Wenn ich rufe dann SubmitChanges() auf meinem DataContext Objekt, wird es die Board property des TaskPin (geerbt von Pin) zu null gesetzt.

public void Save(Pin pin) 
    { 
     // This is empty so no modified members are identified => Correct 
     var modifiedMembers = db.Pins.GetModifiedMembers(pin); 

     // Contains just one entry for the deleted Task entity => Correct 
     var changeSet = db.GetChangeSet(); 

     // This call will immediately set Board property of Pin to null => Wrong! 
     db.SubmitChanges(); 
    } 

Ich gehe davon aus, dass die Task wird gelöscht, weil DeleteOnNull auf true gesetzt ist, aber ich weiß nicht, warum die Board property von Pin auch null eingestellt wird, die in einem NullPointerExceptio oder dass der Pin auch führen wird gelöscht .

Ich habe eine Google-Suche zu diesem Thema, aber ich finde nichts, das mein Problem gelöst hat. Eine Alternative wäre, das Nullen der Board-Eigenschaft zu verhindern und DeleteOnSubmit() für Task manuell aufzurufen.

+0

Wie verwenden Sie datacontext - einmal erstellen oder neu erstellen? Kennen Sie sich mit SQL Profiler aus? Es scheint, dass Sie zwei Transaktionen haben und ich kann Viewer mit Profiler sein. –

+0

Enthält Ihr 'changeSet' einen Nicht-Null-Verweis auf' Board'? Ich vermute, dass Ihr Objektgraph aufgrund anderer Faktoren nicht geladen wird. – Mrchief

+0

@Mrchief was meinst du mit Objektgraph? Das ChangeSet enthält einen Eintrag für das TaskPin, das gelöscht werden soll. –

Antwort

0

Für mich scheint es, dass das Verhalten beabsichtigt ist.

Wenn man sich die Pin Eigenschaft in Aufgabe Klasse wird festgelegt auf Null (DeleteOnNull = true), die dann die Pin in Aufgabe gelöscht werden wird gemäß gelöscht werden removeTask() in TaskPin Klasse.Schauen Sie sich die removePin() Methode in Vorstand Klasse, die Vorstand des Pin auf null setzt. Schauen Sie sich die Vorstand Eigenschaft in Pin Klasse, DeleteOnNull auf true gesetzt, die den Vorstand von Pin Instanz löschen, wenn auf null gesetzt.