linq отношение «один ко многим» хранит только один член списка

Я пытаюсь установить связь «один ко многим» с linq на Windows Phone 8. Моя проблема в том, что в поле EntitySet‹> только один из классов, который должен быть сохранен, действительно сохраняется в базе данных. Поэтому я сделал простой проект, чтобы дать вам представление о моей проблеме. Есть два класса Person и Number. У одного человека может быть много номеров.

Вот числовой класс:

[Table]
class Number
{
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int NumberID { get; set; }

    [Column]
    public int PhoneNumber { get; set; }

}

И класс Person:

[Table]
class Person
{
    private EntitySet<Number> numbers = new EntitySet<Number>();

    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int PersonID { get; set; }

    [Column]
    public string Name { get; set; }

    [Association(Storage = "numbers", ThisKey = "PersonID", OtherKey = "NumberID")]
    public EntitySet<Number> Numbers
    {
        get { return numbers; }
        set
        {
            numbers.Assign(value);
        }
    }
}

Когда я сейчас пытаюсь вставить человека с тремя числами:

        EntitySet<Number> numbers = new EntitySet<Number>();
        DataBase db = new DataBase(App.DBConnectionString);
        Number num1 = new Number() { PhoneNumber = 111111 };
        Number num2 = new Number() { PhoneNumber = 222222 };
        Number num3 = new Number() { PhoneNumber = 333333 };
        Person person = new Person() { Name = "Donald" };
        numbers.Add(num1);
        numbers.Add(num2);
        numbers.Add(num3);
        person.Numbers = numbers;


        try
        {
            db.Persons.InsertOnSubmit(person);
            db.SubmitChanges();
        }
        catch (Exception s)
        {
            // do nothing
        }

А затем попробуйте снова получить данные:

        DataBase db = new DataBase(App.DBConnectionString);
        string text = "";
        foreach (Person person in db.Persons)
        {
            foreach (Number num in person.Numbers)
            {
                text += num.PhoneNumber + System.Environment.NewLine;
            }
        }

        TextBlock.Text = text;

я получаю только первый номер телефона, который является «111111». Интересно, что при втором запуске текстовая строка содержит «111111» и «222222». Это потому, что во втором лице сохраняется второй номер телефона, а в третьем лице — третий номер телефона и так далее. Итак, если вы делаете это достаточно часто, вы получаете: 111111 222222 333333 111111 222222 333333 ... Кстати, если вы перейдете с отладчиком к 'db.Persons.InsertOnSubmit(person);' и посмотрите на «человека», там есть список со всеми тремя числами. Так что должно работать...

Я очень старался, но не могу найти способ сделать это правильно. Однако я подозреваю, что это атрибут [Association].

Вот ссылка на источник, чтобы вы могли получить полную картину, если хотите: https://docs.google.com/file/d/0B5G4zya_BlZyUlU0azVvbVdiajA/edit?usp=sharing


person Robin    schedule 22.08.2013    source источник


Ответы (1)


У меня тоже была такая проблема некоторое время назад. Я добавил в свой код несколько строк, из-за которых он исчез.

Linq2SQL немного волшебен, и иногда что-то (не) работает без видимой причины. Просто чтобы быть полностью уверенным, вы можете реализовать официальное решение One-To-Many, предоставленное Microsoft:

http://msdn.microsoft.com/en-us/library/vstudio/bb386950(v=vs.100).aspx

Также я бы внес следующие коррективы:

[Table]
class Number
{
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int NumberID { get; set; }

    [Column]
    public int _personID { get; set; }

    [Column]
    public int PhoneNumber { get; set; }

    private EntityRef<Person> _person;
    [Association(Storage = "_person", ThisKey = "_personID", OtherKey = "PersonID", IsForeignKey = true)]
    public Person Person
    {
        get { return this._person.Entity; }
        set { 
            this._person.Entity = value;
            if (value != null)
            {
                this._personID = value.PersonID;
            }
        }
    }  
}

И я бы добавил это в конструктор:

public Person()
{
    this._numbers = new EntitySet<Number>(
    delegate (Number entity)
    {
        entity.Person = this;
    },
    delegate (Number entity)
    {
        entity.Person = null;
    });
}

В качестве теста я бы не стал загружать весь объект. Сначала просто проверьте, все ли номера попали в базу данных:

var numbers = db.Numbers.ToList();

Это связано с тем, что L2S на Windows Phone имеет серьезные проблемы с чтением глубоких соединений объектов. Один уровень — это хорошо, но более глубокие отношения игнорируются. Поэтому, если ваш класс Person находится в другом классе, это также может быть проблемой.

Изменить: вы можете добавить параметры в свой контекст БД, чтобы принудительно загрузить глубокую загрузку объекта:

_db = new DBContext("isostore:/mydb.sdf");
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Person>(p => p.Numbers);
_db.LoadOptions = loadOptions;
person Fred    schedule 23.08.2013
comment
Большое спасибо за ответ! Я до сих пор не могу выполнить поиск по людям и получить каждый связанный номер. Но я могу получить идентификатор человека и найти каждый номер, связанный с этим идентификатором. Так что это обходной путь, с которым я могу жить. - person Robin; 25.08.2013
comment
Я добавил образец для DataLoadOptions. Это тоже может помочь. - person Fred; 28.08.2013