Domanda

I'm trying to set up a one to many relationship with linq on Windows Phone 8. My problem is that in the EntitySet<> field only one of the classes which should be stored, really gets stored to the database. So i made a simple Project to give you clue of my problem. There are two classes Person and Number. One Person can have many numbers.

Here is the number class:

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

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

}

And the Person class:

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

When i now try to insert a person with three numbers:

        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
        }

And then try to retrieve the data again:

        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;

i only get the first phone number which is '111111'. Interesting is, that on the second run the text string holds '111111' and '222222'. This is because in the second Person the second phone number is saved and in the third person the third phone number and so on. So if you do that often enough you get: 111111 222222 333333 111111 222222 333333 ... Btw if you jump with the debugger to 'db.Persons.InsertOnSubmit(person);' and look into 'person' there is a list with all three numbers in it. So it should work...

I tried really hard, but i can't figure out a way to get it right. My suspicion though is on the [Association] attribute.

Here is a link to the source so you can get the whole picture if you want: https://docs.google.com/file/d/0B5G4zya_BlZyUlU0azVvbVdiajA/edit?usp=sharing

È stato utile?

Soluzione

I also had that problem a while ago. I added a few lines to my code that made it disappear.

Linq2SQL is a bit magical and sometimes things (don't) work for no obvious reason. Just to be perfectly sure you might want to implement the official One-To-Many solution provided by Microsoft:

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

Also I would make the following adjustments:

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

And I'd add this to the constructor:

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

As a test I would not try to load the entire object. First just check if all numbers have made it to the database:

var numbers = db.Numbers.ToList();

This is because L2S on Windows Phone has serious trouble reading deep object connections. One level is fine but deeper relationships are ignored. So if your Person class resides in another class that could be a problem as well.

Edit: You can add options to your DB context in order to force deep object loading:

_db = new DBContext("isostore:/mydb.sdf");
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Person>(p => p.Numbers);
_db.LoadOptions = loadOptions;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top