Hi Alex, I was moved this discussion here.

My model is the following:

public class Doctors: Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        [Field(Length = 50)]
        public string FulllName{ get; set; }

        [Field]
        public string Email { get; set; }

        [Field]
        [Association(PairTo = "Doctors")]
        public EntitySet<Specialities> Specialities { get; private set; }
    }

public class Specialities: Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        [Field(Length = 50)]
        public string Title { get; set; }

        [Field]
        public bool Activ { get; set; }

        [Field]
        [Association(PairTo = "Specialities")]
        public EntitySet<Doctors> Doctors { get; private set; }
    }

When the domain is built, DO creates the intermediate table as you know.

I have the following LINQ Query to query all the doctors that belong to an specific speciality:

string SpecTitle = string.Empty;
string MedFullName = string.Empty;
string MedEmail = string.Empty;

using (Session.Open(domain))
                    {
                        using (var transactionScope = Transaction.Open())
                        {

                            var spec = Query.Single<Specialities>(1);
                            var list = from m in spec.Doctors
                                       select new { spec.Title, m.FullName, m.Email };

                                      for (var r in list)
                                      {
                                             SpecTitle = r.Title;
                                             MedFullName = r.FullName;
                                             MedEmail = r.Email;
                                      }
                        }

The line where starts the exception is: for (var r in list)

The message exception is: {"Invalid TupleDescriptor. Expected descriptor is TupleDescriptor(Int32, Int32, String, Boolean).\r\nParameter name: difference"}

The stacktrace is the following:

eventArgs.Exception.StackTrace  "   at System.TupleExtensions.MergeWith(Tuple origin, Tuple difference, Int32 startIndex, Int32 length, MergeBehavior behavior)\r\n   at System.TupleExtensions.MergeWith(Tuple origin, Tuple difference, MergeBehavior behavior)\r\n   at Xtensive.Storage.EntityState.Update(Tuple update)\r\n   at Xtensive.Storage.Session.UpdateEntityState(Key key, Tuple tuple, Boolean isStale)\r\n   at Xtensive.Storage.Providers.SessionHandler.RegisterEntityState(Key key, Tuple tuple)\r\n   at Xtensive.Storage.Linq.Materialization.ItemMaterializationContext.Materialize(Int32 entityIndex, Int32 typeIdIndex, TypeInfo type, Pair`1[] entityColumns, Tuple tuple)\r\n   at lambda_method(ExecutionScope , Object[] , Tuple , ItemMaterializationContext )\r\n   at System.DelegateBindExtensions.<>c__DisplayClassa`4.<Bind>b__9(T2 arg2, T3 arg3)\r\n   at Xtensive.Storage.Linq.Materialization.MaterializationHelper.<>c__DisplayClass4`1.<Materialize>b__3(Tuple tuple)\r\n   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()\r\n   at System.EnumerableExtensions.<Batch>d__27`1.MoveNext()\r\n   at System.EnumerableExtensions.<ApplyBeforeAndAfter>d__2f`1.MoveNext()\r\n   at Xtensive.Storage.TransactionalExtensions.<ToTransactional>d__0`1.MoveNext()\r\n   at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()\r\n   at OperacionesSocketServer.Operaciones.Escuchar(String data) in C:\\Users\\Diego\\Documents\\Visual Studio 2008\\Projects\\TestingAspects\\OperacionesSocketServer\\Operaciones.cs:line 141"    string

I see that the tuple descriptor belongs to the Doctor Entity definition, but my goal is to obtain the following output:

Speciality Doctor Email Ophthalmology Francisco Correa fran@gmail.com Ophthalmology Alex Yakunin alex@gmail.com

Thanks in advance.


Updated at 03.06.2010 20:22:55

Ok, sorry Alex, instead of Specialities must be Speciality in the following piece of code, only I was forgotten, because in my original model there is:

[HierarchyRoot]
  public class Speciality : Entity
  {
    [Field, Key]
    public int Id { get; private set; }

    [Field(Length = 50)]
    public string Title { get; set; }

    [Field]
    public bool Activ { get; set; }

    [Field]
    // [Association(PairTo = "Specialities")] // Must lead to an exception!
    [Association(PairTo = "Speciality")]
    public EntitySet<Doctor> Doctors { get; private set; }
  }
}

Ok, I'm going to try with your code and I'm going to tell you if everything works.

Thanks in advance


Updated at 04.06.2010 1:31:23

Always the same exception...

Can I obtain in a concatenated string variable without using the line of code "foreach (var item in list)"? Because in this line of code there is the exception.

The bold part can I concatenate or necessarily I must use "foreach (var item in list)"?

var spec = Query.Single<Speciality>(1);
var list = from m in spec.Doctor
select new { [b]spec.Title, m.FullName, m.Email[/b] };

foreach (var item in list...

Thanks in advance.


Updated at 08.06.2010 3:22:02

First, I have a Windows Service where I use DataObjects.

I have a socket server implementation inside them, and I have some operations that I call with a socket client that I have programmed in the socket server. All the operations until now work well, except an operation that relates Speciality and Doctor entities. As you know early we made a LINQ query that list all the doctors that belong to an specific Speciality.

The following code makes that:

var spec = Query.Single<Speciality>(1);
var list = from m in spec.Doctors
select new { [b]spec.Title, m.FullName, m.Email[/b] };

Trying to obtain the output result, I have the following piece of code:

string outResult;
foreach (var item in list) //There is an exception
{
outResult = item.Title + ", " + item.FullName + ", " + item.Email + ";";
}

Assuming the definition of the Doctor Entity and Speciality, I have the following:

[HierarchyRoot]
  public class Speciality : Entity
  {
    [Field, Key]
    public int Id { get; private set; }

    [Field(Length = 50)]
    public string Title { get; set; }

    [Field]
    public bool Activ { get; set; }

    [Field]
    [Association(PairTo = "Speciality")]
    public EntitySet<Doctor> Doctors { get; private set; }
  }
}

public class Doctor: Entity
    {
        [Field, Key]
        public int Id { get; private set; }

        [Field(Length = 50)]
        public string FulllName{ get; set; }

        [Field]
        public string Email { get; set; }

        [Field]
        [Association(PairTo = "Doctor")]
        public EntitySet<Speciality> Specialities { get; private set; }
    }

I have observed that the exception: {"Invalid TupleDescriptor. Expected descriptor is TupleDescriptor(Int32, Int32, String, Boolean).\r\nParameter name: difference"} relates to the Doctor entity definition, because assuming the data types parameters is the same to the Doctor entity columns, except by the second parameter that belongs the TypeId property that correspond to the DataObjects.net implementation.

Really I dont know why I received this exception. Alex if you need more clarification,just tell me.I hope it is understood. Sorry for my poor english.

Thanks in advance.


Updated at 08.06.2010 13:46:59

Hello Dmitri, I have already this error fixed (Speciality instead of Specialities). The problem is not that.

Hello psulek, just I have omitted the HierarchyRoot attribute here, but I have in my model, sorry I have forgotten.

The following LINQ query that you showed me I have already tested:

select new {Title = spec.Title, FullName = m.FulllName, Email = m.Email}; but without success.

And the same for the following code:

using (Session.Open(domain))
{
    using (var transactionScope = Transaction.Open())
    {
        var spec = Query.Single<Speciality>(1);
        var list = from m in spec.Doctors
                   select new {Title = spec.Title, FullName = m.FulllName, Email = m.Email};

        string outResult;
        foreach (var item in list) //There is an exception
        {
            outResult = item.Title + ", " + item.FullName + ", " + item.Email + ";";
        }
    }
}

I did not add Speciality or Doctor like that, because I have stored already in the tables:

var config = DomainConfiguration.Load("Default");
var domain = Domain.Build(config);

using (Session.Open(domain))
{
    using (var transactionScope = Transaction.Open())
    {
        // Creating new persistent object
        var speciality = new Specialities
        {
            Activ = true,
            Title = "Specialist 1",
        };

        speciality.Doctors.Add(new Doctors
                                   {
                                       FulllName = "House MD.",
                                       Email = "house@md.com"
                                   });

        // Committing transaction
        transactionScope.Complete();
    }
}

Thanks in advance.


Updated at 24.06.2010 3:39:07

Ok, I have two solution, a socket server project and a client socket project, there are three projects in the socket server project:

1) A Class Library named "Aspectos", here there are classes that have some aspects using PostSharp like attributes. 2) Another Class Library named "OperacionesSocketServer", here there is the Model of the database and the list of the operations of the socket server. 3) A Socket Server itself using a Windows Service template.

The problem is HOW CAN I WRITE THE LINQ QUERY

If you test the operations you are going to see all work but the operation VME is the problem.

Obs: My main language is spanish, there is difference in the names of the Entities, etc. for example Specialities is Especialidades and Doctors is Medicos.

Here are the files

[attachment=1:371mhmby]TestingAspects.rar[/attachment:371mhmby] [attachment=0:371mhmby]SocketAsyncClient.rar[/attachment:371mhmby]


Updated at 06.07.2010 1:50:34

No, the problem is not the serialization, because I do not pass the LINQ query between client and server. If you could download the code and test you may see which is the error. The error itself is the LINQ query, relationship between the type of one or more of the fields of the entities. Try to test please, because I was tried many times but without success.

Thanks in advance.


Updated at 08.07.2010 1:39:29

I understand you Alex, I have already read the manual, but is not precise, specially because I have two entities and the relationship is many to many and I need a simple LINQ Query that solve my requirements, I saw that in the manual there is an example, but when I test with my application does not work and the exception appears.

var spec = Query.Single<Speciality>(1);
var list = from m in spec.Doctors
select new { [b]spec.Title, m.FullName, m.Email[/b] };
string outResult;
foreach (var item in list) //There is an exception
{
outResult = item.Title + ", " + item.FullName + ", " + item.Email + ";";
}

If you see, the problem seems very simple, but until now I can't resolved. I bellieve that my entities definition Speciality and Doctor are correct.

This thread was imported from our support forum. The original discussion may contain more detailed answer. Original topic by DiegoCorrea.

asked Jun 03 '10 at 03:35

Editor's gravatar image

Editor
46148156157


One Answer:

Alex (Xtensive) wrote:

It seems there is a bug in Domain model builder allowing you to use [Association(PairTo = ...)] on both sides of relationship - that's wrong, this attribute must be used only on one side. The side it is applied to becomes "virtual": no data structures are created for it, it relies on structures created for another side instead.

Try to fix this issue first. I'll create a bug report about this.

Btw, I think you must switch from using "Doctors" and "Specialities" to "Doctor" and "Speciality". Plural class names are quite untypical in .NET world.


Alex (Xtensive) wrote:

Ok, I just implemented everything in test. Conclusions:

1) Bug in code you've provided: for (var r in list) ... doesn't compile - by obvious reason.

2) Absence of [HierarchyRoot] at your types was leading to this exception:

System.ArgumentException : Type 'Speciality' is not registered.
at Xtensive.Storage.Model.TypeInfoCollection.get_Item(Type key) in TypeInfoCollection.cs: line 65
at Xtensive.Storage.Key.Create(Domain domain, Type type) in Key.cs: line 341
at Xtensive.Storage.Entity..ctor() in Entity.cs: line 623
at Xtensive.Storage.Tests.Issues.Issue679And681.Speciality..ctor()
at Xtensive.Storage.Tests.Issues.Issue679And681Test.BuildTest() in Issue679,681_EntitySetRelatedBugs.cs: line 67

3) Bug with [PairTo] was actually a "feature" - i.e. everything was ok if you declare pairing on both sides. I added the following check: if multiplicity is one-to-one or many-to-many, an exception will be thrown, since in this case it's impossible to determine which side of relationship must be "virtual". Before this new check this was dependent on type registration order, which is wrong (reg. order change would lead to schema change).

So now you can use such declarations only with many-to-one relationship. But I should mention everything worked fine even without this fix.

Test code is here: http://goo.gl/qaWW

Its output:

Speciality1 Doctor1 email1@host.com
Speciality1 Doctor2 email2@host.com

Alex (Xtensive) wrote:

Just checked your case:

1032/7     INFO Core.Diagnostics         Core.Diagnostics log initialized.
 1095/7     INFO Core.Diagnostics         Storage.Building log initialized.
 1218/7     INFO Core.Diagnostics             Storage log initialized.
 1819/7     INFO Core.Diagnostics             Storage.Providers.Sql log initialized.
 2724/7     INFO Core.Diagnostics             Modelling log initialized.
 4208/7     INFO Core.Diagnostics         Storage.Tests log initialized.
 4209/7    ERROR Storage.Tests            Xtensive.Storage.Tests.Issues.Issue679And681Test
 4210/7    ERROR Storage.Tests            Exception!
Original error:
Xtensive.Storage.DomainBuilderException: Paired field 'Speciality' was not found in 'Doctor' type.
   at Xtensive.Storage.Building.Builders.AssociationBuilder.BuildPairedAssociation(AssociationInfo slave, String masterFieldName) in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Building\Builders\AssociationBuilder.cs:line 49
   at Xtensive.Storage.Building.Builders.ModelBuilder.BuildAssociations() in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Building\Builders\ModelBuilder.cs:line 152
   at Xtensive.Storage.Building.Builders.ModelBuilder.BuildModel() in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Building\Builders\ModelBuilder.cs:line 102
   at Xtensive.Storage.Building.Builders.ModelBuilder.Run() in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Building\Builders\ModelBuilder.cs:line 58
   at Xtensive.Storage.Building.Builders.DomainBuilder.BuildModel() in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Building\Builders\DomainBuilder.cs:line 213
   at Xtensive.Storage.Building.Builders.DomainBuilder.BuildDomain(DomainConfiguration configuration, DomainBuilderConfiguration builderConfiguration) in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Building\Builders\DomainBuilder.cs:line 60
   at Xtensive.Storage.Upgrade.UpgradingDomainBuilder.BuildStageDomain(UpgradeStage stage) in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Upgrade\UpgradingDomainBuilder.cs:line 74
   at Xtensive.Storage.Upgrade.UpgradingDomainBuilder.Build(DomainConfiguration configuration) in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Upgrade\UpgradingDomainBuilder.cs:line 54
   at Xtensive.Storage.Domain.Build(DomainConfiguration configuration) in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage\Domain.cs:line 225
   at Xtensive.Storage.Tests.AutoBuildTest.BuildDomain(DomainConfiguration configuration) in E:\My Projects\Hg\DataObjects.Net\Xtensive.Storage\Xtensive.Storage.Tests.Core\AutoBuildTest.cs:line 71

Xtensive.Storage.DomainBuilderException : Paired field 'Speciality' was not found in 'Doctor' type.
at Xtensive.Storage.Building.Builders.AssociationBuilder.BuildPairedAssociation(AssociationInfo slave, String masterFieldName) in AssociationBuilder.cs: line 49
at Xtensive.Storage.Building.Builders.ModelBuilder.BuildAssociations() in ModelBuilder.cs: line 152
at Xtensive.Storage.Building.Builders.ModelBuilder.BuildModel() in ModelBuilder.cs: line 102
at Xtensive.Storage.Building.Builders.ModelBuilder.Run() in ModelBuilder.cs: line 58
at Xtensive.Storage.Building.Builders.DomainBuilder.BuildModel() in DomainBuilder.cs: line 213
at Xtensive.Storage.Building.Builders.DomainBuilder.BuildDomain(DomainConfiguration configuration, DomainBuilderConfiguration builderConfiguration) in DomainBuilder.cs: line 60
at Xtensive.Storage.Upgrade.UpgradingDomainBuilder.BuildStageDomain(UpgradeStage stage) in UpgradingDomainBuilder.cs: line 74
at Xtensive.Storage.Upgrade.UpgradingDomainBuilder.Build(DomainConfiguration configuration) in UpgradingDomainBuilder.cs: line 54
at Xtensive.Storage.Domain.Build(DomainConfiguration configuration) in Domain.cs: line 225
at Xtensive.Storage.Tests.AutoBuildTest.BuildDomain(DomainConfiguration configuration) in AutoBuildTest.cs: line 76
at Xtensive.Storage.Tests.AutoBuildTest.TestFixtureSetUp() in AutoBuildTest.cs: line 31

So likely, there was something different.


Alex (Xtensive) wrote:

Can you send us your sample?

Yes, you can write "select spec.Title + m.FullName + m.Email" there, but in this case this will be executed as SQL, so you will get just this string as result, none of objects will be materialized (i.e. if you'll use them later in the same transaction, they'll need to be fetched).


Dmitri Maximov (Xtensive) wrote:

Hello Diego,

it seems that you have a mistake in the model, I mean, values of PairTo property of Association attribute were wrong. Here is the correct snippet:

[Field]
[Association(PairTo = "Specialities")]
public EntitySet<Doctor> Doctors { get; private set; }

&

[Field]
[Association(PairTo = "Doctors")]
public EntitySet<Speciality> Specialities { get; private set; }

psulek wrote:

First, I have a Windows Service where I use DataObjects. I have a socket server implementation inside them, and I have some operations that I call with a socket client that I have programmed in the socket server. All the operations until now work well, except an operation that relates Speciality and Doctor entities. As you know early we made a LINQ query that list all the doctors that belong to an specific Speciality. The following code makes that: var spec = Query.Single<speciality>(1); var list = from m in spec.Doctors select new { [b]spec.Title, m.FullName, m.Email[/b] }; Trying to obtain the output result, I have the following piece of code: string outResult; foreach (var item in list) //There is an exception { outResult = item.Title + ", " + item.FullName + ", " + item.Email + ";"; } Assuming the definition of the Doctor Entity and Speciality, I have the following: [HierarchyRoot] public class Speciality : Entity { [Field, Key] public int Id { get; private set; } [Field(Length = 50)] public string Title { get; set; } [Field] public bool Activ { get; set; } [Field] [Association(PairTo = "Speciality")] public EntitySet<doctor> Doctors { get; private set; } } } public class Doctor: Entity { [Field, Key] public int Id { get; private set; } [Field(Length = 50)] public string FulllName{ get; set; } [Field] public string Email { get; set; } [Field] [Association(PairTo = "Doctor")] public EntitySet<speciality> Specialities { get; private set; } } I have observed that the exception: {"Invalid TupleDescriptor. Expected descriptor is TupleDescriptor(Int32, Int32, String, Boolean).\r\nParameter name: difference"} relates to the Doctor entity definition, because assuming the data types parameters is the same to the Doctor entity columns, except by the second parameter that belongs the TypeId property that correspond to the DataObjects.net implementation. Really I dont know why I received this exception. Alex if you need more clarification,just tell me.I hope it is understood. Sorry for my poor english. Thanks in advance.

I found 2 errors in your sample: 1. on both classes you missing attribute [HierarchyRoot] 2. you have wrong construction of anonymous type in final select projection, you have:

select new {spec.Title, m.FulllName, m.Email};

But definition must be like that:

select new {Title = spec.Title, FullName = m.FulllName, Email = m.Email};

Important here is that you must specify names of properties for anonymous type like Title, FullName, Email

Here is working code that i update:

var config = DomainConfiguration.Load("Default");
var domain = Domain.Build(config);

using (Session.Open(domain))
{
    using (var transactionScope = Transaction.Open())
    {
        // Creating new persistent object
        var speciality = new Specialities
        {
            Activ = true,
            Title = "Specialist 1",
        };

        speciality.Doctors.Add(new Doctors
                                   {
                                       FulllName = "House MD.",
                                       Email = "house@md.com"
                                   });

        // Committing transaction
        transactionScope.Complete();
    }
}

using (Session.Open(domain))
{
    using (var transactionScope = Transaction.Open())
    {
        var spec = Query.Single<Specialities>(1);
        var list = from m in spec.Doctors
                   select new {Title = spec.Title, FullName = m.FulllName, Email = m.Email};

        string outResult;
        foreach (var item in list) //There is an exception
        {
            outResult = item.Title + ", " + item.FullName + ", " + item.Email + ";";
        }
    }
}

psulek wrote:

And which version of DO4 do you have? I have tested it on 4.3RC2 with success. I dont know how to help you more, can you post sample (zip with solution and project) which does not work for you. Or some details how are named your existing DB, and sample data information you have in existing tables, that i can reconstruct your case properly.


Alex (Xtensive) wrote:

Does this correct: the question isn't about how to perform the LINQ query (that's described in Manual), but how to serialize client-side query, send it to server and get back the results?

If I'm wrong, please describe what you're going to perform more precisely. Unfortunately, I really don't have enough time to figure out this from posted solutions...


psulek wrote:

if you want to pass DO linq query from client to server, you must serialized linq query expression on client side like this:

var query = Query.All<Person>().Where(person => person.Name = "xyz");
var serializedExpression = query.Expression.ToSerializableExpression();
byte[] buffer;
using (MemoryStream serializationStream = new MemoryStream())
{
  new BinaryFormatter().Serialize(serializationStream, serializedExpression);
  buffer = serializationStream.GetBuffer();
}

here buffer will contains byte array of serialized expression which will be passed to server (by any channel-wcf/socket/...)

and deserialize byte array to expression on server side:

byte[] inputData = ...

using(MemoryStream serializationStream = new MemoryStream(buffer))
{
   serializationStream.Position = 0;
   var serializedExpression = (SerializableExpression)new BinaryFormatter().Deserialize(serializationStream);
   var deserializedExpression = serializedExpression.ToExpression();
   var query = new Xtensive.Storage.Linq.Queryable<Person>(expression);
}

// iterate 'query' by foreach, etc...

Here you can also on client side serialize assembly qualified type name of type T you are quering agains Query.All<t> and put this information into buffer. On server side you can deserialize this assembly qualified type name and build runtime Type (Type.GetType(string)). Server side example:

Type entityType = deserializeEntityType();
Type makeGenericType = typeof(Queryable<>).MakeGenericType(entityType);
IQueryable<Entity> queryable = Activator.CreateInstance(makeGenericType, deserializedExpression);

Alex (Xtensive) wrote:

We can download & task the code, but normally we do this for paid customers only. Another reason is language: most of us know English and Russian, but not Spanish. Imagine we'd ask to to study the code with Russian type and field names.

So I'd recommend you to try narrow down the case. Questions like "The problem is HOW CAN I WRITE THE LINQ QUERY" look simply strange, taking into account there is a large part in manual about this. I.e. ask more precise question.

E.g. I simply don't understand what is implied here, although I read everything. If someone else understands the case, I'd be happy to hear the explanation...

I'm sorry for such an answer, but this is the case when it's difficult to help, because there is no precise question.

answered Jun 03 '10 at 04:28

Editor's gravatar image

Editor
46148156157

Ok, it seems the simplest way is to send us the whole soultion, or to share it here.

(Jun 03 '10 at 04:28) Alex Yakunin Alex%20Yakunin's gravatar image

DiegoCorrea wrote: If you need other details or if you have doubts about the project let me know please.

(Jun 03 '10 at 04:28) Editor Editor's gravatar image

DiegoCorrea wrote: Any ideas?

(Jun 03 '10 at 04:28) Editor Editor's gravatar image

DiegoCorrea wrote: Hi Alex, I have done your recommendation about the PairTo, only in one of the Entities, but still appearing the same exception.

There is a way to obtain the output that I want and save in a string variable?

Thanks four help provided always.

(Jun 03 '10 at 04:28) Editor Editor's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA