The mapping of interface member [...] is not supported.
-
Tuesday, April 08, 2008 9:58 AMWe have tables that have the same members and so we want to access them using the same methods.
So we created interfaces that the classes created by the DBML file implement and then created generic methods.
Everything works fine, we can even access each elements of the IQueryable one by one using First() or Skip().First() but the application crashes when we try have a GetEnumerator().
The exception thrown is "NotSupportedException: The mapping of interface member IMyInterface.value_text is not supported."
Code Snippet// Applied an interface to the class created by the DBML
public interface IMyInterface { string value_text { get; set; } }
public partial class tbl_product_value : IMyInterface {};
// The generic method
public void foo<T>(System.Data.Linq.Table<T> table) where T : class, IMyInterface
{
// The query
var query = (
from var in table
where var.value_text == "bar"
//where var.value_text.StartsWith( "A" ) // <= Even this works with GetEnumerator() !
select var );
// Accessing each elements one by one
for( int i=0; i<query.Count(); ++i )
{
var value = query.Skip(i).First(); // <= This works fine ! (but really slow)
Console.Out.WriteLine( value.value_text );
}
// Trying to get the GetEnumerator()
foreach( var value in query ) // <= Fails here with "NotSupportedException: The mapping of interface member IMyInterface.value_text is not supported."
{
Console.Out.WriteLine( value.value_text );
}
}
// The calling statement
foo<tbl_product_value>( engine.Context.tbl_product_values );
I don't understand why L2S is unable to map the member value_text since this member HAS the mapping attributes. Even if it is an interface implementation.
The simple proof of that is that when accessing elements one by one works perfectly.
But of course, the problem with accessing each entries one by one is really slow since it execute a new SQL query for each rows (plus the .Count())
Answers
-
Wednesday, April 09, 2008 3:34 PM
Hi,
yes I understand your concerns about .AsEnumerable() (it was my first attempt).
The more important point is that using
var qry1 = from o in table
where o.Text.Equals("XYZ")
select o;
will work.
This is translated to
SELECT [t0].[ID], [t0].[Text], [t0].[Int1]
FROM [dbo].[TestTable1] AS [t0]
WHERE [t0].[Text] = @p0
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [XYZ]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8and shows the right result.
The funny thing is that 'where o.Text == "XYZ"' is translated to the same Sql statement (you can check this in Debugger) but gives the exeception message.
regards
Philipp
All Replies
-
Wednesday, April 09, 2008 8:04 AM
Hi,
I guess L2S doesn't allow it to prevent infinite loop. Maybe you call foo<tbl_product_value>(...) and this will create an instance of tbl_product_value which again calls foo<tbl_product_value>....
I'm not really sure if this is the reason for the message but I suppose it.
What's happen if you make this generic method static. From what I can see the is no link to instance data.
regards
Philipp
-
Wednesday, April 09, 2008 9:14 AM
Hello,
To me, you can as well call a non generic method foo that will create an instance of tbl_product_value which then calls foo again. I don't see the link with the generics.
The only difference is that inside the method, tbl_product_value.value_text is referenced by its interface member instead of its class member. If you change the declaration from
public static void foo<T>(System.Data.Linq.Table<T> table) where T : class, IMyInterfaceto
public static void foo<T>(System.Data.Linq.Table<T> table) where T : tbl_product_value, IMyInterface
everything re-works fine. But this is useless in our case...
I really feel that as a "missing little code part"(bug?) in the Microsoft's library.
I don't understand what you mean by making this method static. Declaring foo as
public static void foo<T>(System.Data.Linq.Table<T> table)
doesn't change anything. There is no reference to class members in this example, but this is only an example.
Thanks,
Alain
-
Wednesday, April 09, 2008 12:23 PM
Hi,
to make sure I got it.
Two tables
Code SnippetCREATE
TABLE [dbo].[TestTable1]([ID] [int]
IDENTITY(1,1) NOT NULL,[Text] [nvarchar]
(50) NOT NULL,[Int1] [int]
NOT NULL,....
CREATE
TABLE [dbo].[TestTable2]([ID] [int]
IDENTITY(1,1) NOT NULL,[Text] [nvarchar]
(50) NOT NULL,[Date2] [smalldatetime]
NOT NULL,....
An interface and partial classes to access the field Text in both tables
Code Snippetpublic interface IMyInterface
{
string Text { get; set; }}
partial class TestTable2 :IMyInterface{
}
partial class TestTable1 :IMyInterface{
}
And a generic method in the program which can access the common field
Code Snippetclass Program
{
static void Main(string[] args){
DBDataContext DC = new DBDataContext();DC.Log =
Console.Out;foo(DC.TestTable1s);
foo(DC.TestTable2s);
Console.ReadKey();}
static void foo<T>(Table<T> table) where T : class, IMyInterface{
var qry1 = from o in table.AsEnumerable<T>()// this will run
// gives the exception
var
qry1 = from o in table
where o.Text == "XYZ" select o; foreach (var item in qry1){
Console.WriteLine(item.Text);}
}
}
var qry1 = from o in table
gives the exeception and has an Sql of
SELECT [t0].[ID], [t0].[Text], [t0].[Int1]
FROM [dbo].[TestTable1] AS [t0]
WHERE [t0].[Text] = 'XYZ'var qry1 = from o in table.AsEnumerable<T>()
reads the whole table and (I guess) uses Linq To Objects to find the object
The following will do the job too
var qry1 = from o in table where o.Text.Equals("XYZ") select o;and again with the Sql
SELECT [t0].[ID], [t0].[Text], [t0].[Int1]
FROM [dbo].[TestTable1] AS [t0]
WHERE [t0].[Text] = @p0
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [XYZ]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8XYZ
I don't know what's wrong with
var qry1 = from o in table
where o.Text == "XYZ"
select o;regards
Philipp
-
Wednesday, April 09, 2008 1:57 PMYes, calling .AsEnumerable() will do the job since it will retreive all the objects into an array or something before executing the .Where().
But this is really not acceptable since we have set some DataLoadOptions to the context to automatically load related objects and accelerate the following calls. At the end, this would be equivalent to loading the whole database into memory... :-/
Even better than that, if you take each elements one by one, it all works fine (see my first post of the thread):
for( int i=0; i<query.Count(); ++i )
{
var value = query.Skip(i).First(); // <= This works fine ! (but really slow)
}
To be honest, I have already posted a similar thread (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3029845&SiteID=1) but received no real answer.
Do you know where else I can ask?
Many thanks,
Alain -
Wednesday, April 09, 2008 3:34 PM
Hi,
yes I understand your concerns about .AsEnumerable() (it was my first attempt).
The more important point is that using
var qry1 = from o in table
where o.Text.Equals("XYZ")
select o;
will work.
This is translated to
SELECT [t0].[ID], [t0].[Text], [t0].[Int1]
FROM [dbo].[TestTable1] AS [t0]
WHERE [t0].[Text] = @p0
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [XYZ]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8and shows the right result.
The funny thing is that 'where o.Text == "XYZ"' is translated to the same Sql statement (you can check this in Debugger) but gives the exeception message.
regards
Philipp
-
Wednesday, April 09, 2008 3:40 PMYes, you are right, this seems to works ok. We will try to use .Equals() from now on.
Still it would be better to warn MSFT about that since it may hide a bigger bug, no?
Huge Thanks,
Alain -
Wednesday, April 09, 2008 4:16 PM
Sure, can you change this thread to a bug report? If you choose another way can you please post a link here that I can keep track of it. I'm curious about the answer why == and .Equals() are differ in the way they are processed.
regards
Philipp
-
Wednesday, April 09, 2008 4:53 PM"change this thread to a bug report"... well well well... yes yesyes... I would be pleased to do that but... erm... how exactly you do that? ;-)
I looked around and in the FAQ but found no way. Google pointed me to connect.microsoft.com but this is to create a new bug from scratch...
So, if you could point me to the "change this thread to a bug report" button, I would be happy to click on it :-D
Or better so, if you want to do it, feel free ;-) -
Wednesday, April 09, 2008 7:54 PM
Sorry, I saw bug threads in the vb forums but this only a pilot project available there.
If you want, I can report it at the connect site and attach my test files. I only need some time and i will post it here if I have done it.
greetings
Philipp
-
Monday, September 01, 2008 5:19 AM
GOOD... the solution that use "Equals" instead of "==" is good but reason is uncovered yet...
highlight it. Any internal expertise gives feedback ???..
-
Monday, September 01, 2008 9:13 AM
Nope, sorry.
Didn't took the time too search how to report bugs...
Anyway, we are writing our own QueryProvider and '==' and '.Equals()' have a totally different representation internally. So this should be why...
Alain -
Tuesday, April 21, 2009 5:55 AMMark up!This is really a strange phenomenon that 'Equals' takes effect whereas '==' shows little help.Now i am intending to build some 'interface-supported' queries to generalize many similar codes likewhere product.ProductId = XX ( where T.EntityId = XX )

