6

次のエンティティ/テーブルがあります。

  • Board: 1 つのボードに多くのピンを配置できます
  • Pin: 1 つのボードに 1 つのピンが割り当てられます。このエンティティは抽象的であり、異なる実装を持つ子を持っています。親ピン エンティティに属するすべての子InheritanceMappingは、ピン テーブルに保存され、Discriminator column
    • TaskPin: これは pin の 1 つの子実装です。多くのタスクを持つことができます。
  • Task: 1 つの TaskPin に 1 つのタスクが割り当てられます

構造をより明確にするためのコードを次に示します。

[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()
    {

    }
}

を作成TaskPinしてボードに割り当てます。次に、2 つのタスクを作成し、TaskPin に割り当てます。これはうまくいきます。Tasksから1 つ以上を実行しようとすると、問題が発生しTaskPinます。

    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);
        }
    }

オブジェクトで then を呼び出すと、(Pin から継承された) TaskPin の が に設定SubmitChanges()されます。DataContextBoard propertynull

    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();
    }

Taskが true に設定されているため、 が削除されることを期待していますが、ピンの も に設定されているDeleteOnNull理由がわかりません。または、ピンも削除されます。Board propertynullNullPointerExceptio

このトピックについて Google 検索を行いましたが、問題を解決するものは見つかりませんでした。別の方法は、Board プロパティの null 化を防ぎ、DeleteOnSubmit()Task を手動で呼び出すことです。

4

1 に答える 1

0

私には、動作が意図されているように見えます。

TaskクラスのPinプロパティを見ると、Null ( DeleteOnNull = true ) で削除されるように設定されており、タスクのピンTaskPinクラスのremoveTask()に従って削除されます。次に、ピンのBoardを nullに設定するBoardクラスのremovePin()メソッドを見てください。次に、 PinクラスのBoardプロパティを見てください。DeleteOnNullは true に設定されており、null に設定するとPinインスタンスからBoardが削除されます。

于 2015-01-14T06:41:09.230 に答える