ObjectDataSource and Linq. Please, help! I don't know what else totry. Thank You.

S

shapper

Hello,

I used a "Linq to SQL classes" in VS 2008 to map the tables of a
database: MyDbDataContext

One of the tables is named Tags and has 2 columns: TagID and Text.
This table is related to a second table named Articles through a table
ArticlesTags.

I would like to use an ObjectDataSource as a layer between my data and
a ListView.

In my page I created the following:

private void odsTags_Init(object sender, EventArgs e)
{
odsTags.ID = "odsTags";
odsTags.SelectMethod = "GetTags";
odsTags.TypeName = "MyDbDataContext";
}

public static ICollection GetTags()
{
MyDbDataContext database = new MyDbDataContext();
var query = from t in db.Tags
select new
{
TagId = t.TagId,
TagText = t.TagText,
Active = t.ArticlesTags.Any
};
return tags;
}

I get the following error:
ObjectDataSource 'odsTags' could not find a non-generic method
'GetTags' that has no parameters.

I have no idea what I am doing wrong. I am not able to solve it!
I tried to Google for a solution but I didn't find it. I don't know
what I am doing wrong.

This is the first time I use an ObjectDataSource with a Linq
DataContext.

Thanks,
Miguel
 
J

Jon Skeet [C# MVP]

shapper said:
I used a "Linq to SQL classes" in VS 2008 to map the tables of a
database: MyDbDataContext

One of the tables is named Tags and has 2 columns: TagID and Text.
This table is related to a second table named Articles through a table
ArticlesTags.

I would like to use an ObjectDataSource as a layer between my data and
a ListView.

In my page I created the following:

private void odsTags_Init(object sender, EventArgs e)
{
odsTags.ID = "odsTags";
odsTags.SelectMethod = "GetTags";
odsTags.TypeName = "MyDbDataContext";
}

public static ICollection GetTags()
{
MyDbDataContext database = new MyDbDataContext();
var query = from t in db.Tags
select new
{
TagId = t.TagId,
TagText = t.TagText,
Active = t.ArticlesTags.Any
};
return tags;
}

That's not your actual code - note the value returned from GetTags().
I get the following error:
ObjectDataSource 'odsTags' could not find a non-generic method
'GetTags' that has no parameters.

Is your type name really just MyDbDataContext with no namespace? That's
the first thing to try.
 
S

shapper

That's not your actual code - note the value returned from GetTags().


Is your type name really just MyDbDataContext with no namespace? That's
the first thing to try.

Yes, it is my code!

I just did a mistake when converting from VB.NET, which I am using for
this example, to C#.

I now create a sample which is only a web site with Sample.Aspx and
LabDataContext.

I always get the same error ...

Could someone please provide me a work example. I am going crazy.

The only way I was able to make this work was doing the following:

I placed the GetTags inside "Extensibility Method Definitions" region
in LabDataContext class using the following:

<DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
Public Shared Function GetTags() As IQueryable
Dim database As New LabDataContext
Dim tags = From t In database.Tags _
Select t.TagID, _
t.Text, _
Active = t.ArticlesTags.Any
Return tags
End Function ' GetTags

Now I get the following error:

ListView with id 'ListView1' must have a data source that either
implements ICollection or can perform data source paging if
AllowPaging is true.

Then I changed to:

<DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
Public Shared Function GetTags() As ICollection
Dim database As New LabDataContext
Dim tags = From t In database.Tags _
Select t.TagID, _
t.Text, _
Active = t.ArticlesTags.Any
Return tags.ToList
End Function ' GetTags

Now it works but I am not sure if this is the right way to do this.
Any idea?
I would prefer to have the GetTags methods outside the DataContext.

Finally, I tried to add a DeleteMethod to my ObjectDataSource:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetTags" DeleteMethod="DeleteTag"
TypeName="LabDataContext">
<DeleteParameters>
<asp:parameter Type="Object" Name="Tag"></asp:parameter>
</DeleteParameters>
</asp:ObjectDataSource>

And I get the following error:

ObjectDataSource 'ObjectDataSource1' could not find a non-generic
method 'DeleteTag' that has parameters: Tag, TagID.

I am using the "Tag" delete parameter because I was thinking in using
the default method inside "Extensibility Method Definitions" region in
LabDataContext class:

Partial Private Sub DeleteTag(ByVal instance As Tag)
End Sub

I have been Goggling for information on how to implement
ObjectDataSource with a Linq to SQL classes but until now I wasn't
able to find anything.

Could someone, please, advise me on the issues I just posted.

Thank You,

Miguel
 
J

Jon Skeet [C# MVP]

Yes, it is my code!

I just did a mistake when converting from VB.NET, which I am using for
this example, to C#.

Then it's not your code - your code is the VB.NET code.

You presented us code which wouldn't compile. As you told us about
something failing *other* than compilation, that means the code you
presented wasn't the code you were trying to use.

Now I get the following error:

ListView with id 'ListView1' must have a data source that either
implements ICollection or can perform data source paging if
AllowPaging is true.

Do you require paging?
Then I changed to:

<DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
Public Shared Function GetTags() As ICollection
Dim database As New LabDataContext
Dim tags = From t In database.Tags _
Select t.TagID, _
t.Text, _
Active = t.ArticlesTags.Any
Return tags.ToList
End Function ' GetTags

Now it works but I am not sure if this is the right way to do this.
Any idea?
I would prefer to have the GetTags methods outside the DataContext.

So put it outside the DataContext - I'm afraid I don't see the problem
with doing so.
Finally, I tried to add a DeleteMethod to my ObjectDataSource:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetTags" DeleteMethod="DeleteTag"
TypeName="LabDataContext">
<DeleteParameters>
<asp:parameter Type="Object" Name="Tag"></asp:parameter>
</DeleteParameters>
</asp:ObjectDataSource>

And I get the following error:

ObjectDataSource 'ObjectDataSource1' could not find a non-generic
method 'DeleteTag' that has parameters: Tag, TagID.

I am using the "Tag" delete parameter because I was thinking in using
the default method inside "Extensibility Method Definitions" region in
LabDataContext class:

Partial Private Sub DeleteTag(ByVal instance As Tag)
End Sub

Unless I'm mistaken, you've told ASP.NET to try to find a method with
a parameter of type Object, not of type Tag. However, at this point
it's really an ASP.NET question more than LINQ - the LINQ side of
things is reasonably irrelevant. You might want to ask on the ASP.NET
newsgroup - particularly as there are more likely to be VB developers
there than here.

Jon
 
S

shapper

Then it's not your code - your code is the VB.NET code.

You presented us code which wouldn't compile. As you told us about
something failing *other* than compilation, that means the code you
presented wasn't the code you were trying to use.




Do you require paging?




So put it outside the DataContext - I'm afraid I don't see the problem
with doing so.









Unless I'm mistaken, you've told ASP.NET to try to find a method with
a parameter of type Object, not of type Tag. However, at this point
it's really an ASP.NET question more than LINQ - the LINQ side of
things is reasonably irrelevant. You might want to ask on the ASP.NET
newsgroup - particularly as there are more likely to be VB developers
there than here.

Jon

Hi Jon,

The moment I put it outside the DataContext I get the error:
ObjectDataSource 'ObjectDataSource1' could not find a non-generic
method 'GetTags' that has no parameters.

This is what is driving me crazy. I really don't see any reason why
this does not work.

Yes I need paging and that was why I am return the tags as a
Collection.

It is irrelevant to me if the help is in VB.NET or C#. I write in
VB.NET only because it is faster to me.

Here is my entire code. Maybe someone can see if I am doing something
wrong (I converter everything to C#):

MyPage.ASPX

<%@ Page Language="VB" AutoEventWireup="false"
CodeFile="ListViewDesign.aspx.vb"
Inherits="ListViewDesign" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>List View Design</title>
</head>
<body>
<form id="fListViewDesign" runat="server">
<asp:ListView ID="ListView1" runat="server"
DataSourceID="ObjectDataSource1" DataKeyNames="TagID"
InsertItemPosition="FirstItem">
<AlternatingItemTemplate>
<tr style="">
<td>
<asp:Label ID="TagText" runat="server" Text='<%#
Eval("Text") %>' />
</td>
<td>
<asp:LinkButton ID="EditButton" runat="Server" Text="Edit"
CommandName="Edit" />
<asp:LinkButton ID="DeleteButton" runat="Server"
Text="Delete" CommandName="Delete" />
</td>
</tr>
</AlternatingItemTemplate>
<LayoutTemplate>
<table runat="server">
<tr runat="server">
<td runat="server">
<table id="itemPlaceholderContainer" runat="server"
border="0" style="">
<tr runat="server" style="">
<th runat="server">
Tag Text
</th>
<th runat="server">
Command
</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
<tr runat="server">
<td runat="server" style="">
<asp:DataPager ID="DataPager1" runat="server">
<Fields>
<asp:NextPreviousPagerField ButtonType="Button"
ShowFirstPageButton="True" ShowLastPageButton="True" />
</Fields>
</asp:DataPager>
</td>
</tr>
</table>
</LayoutTemplate>
<InsertItemTemplate>
<tr style="">
<td>
<asp:Button ID="InsertButton" runat="server"
CommandName="Insert" Text="Insert" />
<asp:Button ID="CancelButton" runat="server"
CommandName="Cancel" Text="Clear" />
</td>
<td>
<asp:TextBox ID="TagTextTextBox" runat="server" Text='<%#
Bind("Text") %>' />
</td>
</tr>
</InsertItemTemplate>
<SelectedItemTemplate>
<tr style="">
<td>
<asp:Label ID="TagText" runat="server" Text='<%#
Eval("Text") %>' />
</td>
</tr>
</SelectedItemTemplate>
<EmptyDataTemplate>
<table runat="server" style="">
<tr>
<td>
No data was returned.
</td>
</tr>
</table>
</EmptyDataTemplate>
<EditItemTemplate>
<tr style="">
<td>
<asp:Button ID="UpdateButton" runat="server"
CommandName="Update" Text="Update" />
<asp:Button ID="CancelButton" runat="server"
CommandName="Cancel" Text="Cancel" />
</td>
<td>
<asp:TextBox ID="TagTextTextBox" runat="server" Text='<%#
Bind("Text") %>' />
</td>
</tr>
</EditItemTemplate>
<ItemTemplate>
<tr style="">
<td>
<asp:Label ID="TagText" runat="server" Text='<%#
Eval("Text") %>' />
</td>
<td>
<asp:LinkButton ID="EditButton" runat="Server" Text="Edit"
CommandName="Edit" />
<asp:LinkButton ID="DeleteButton" runat="Server"
Text="Delete" CommandName="Delete" />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
SelectMethod="GetTags" TypeName="LabDataContext">
</asp:ObjectDataSource>
</form>
</body>
</html>


MyPage.ASPX.VB

Imports System
Imports System.ComponentModel

Partial Class ListViewDesign
Inherits System.Web.UI.Page

' GetTags
<DataObjectMethodAttribute(DataObjectMethodType.Select, True)> _
Public Shared Function GetTags() As ICollection

' Create database
Dim database As New LabDataContext

' Select tags
Dim tags = From t In database.Tags _
Select t.TagID, _
t.Text, _
Active = t.ArticlesTags.Any

' Return tags
Return tags

End Function ' GetTags

End Class
 
J

Jon Skeet [C# MVP]

shapper said:
The moment I put it outside the DataContext I get the error:
ObjectDataSource 'ObjectDataSource1' could not find a non-generic
method 'GetTags' that has no parameters.

But did you update ObjectDataSource1 to point at the new type (or
wherever you put it) at the same time? If not, it's no wonder that it
couldn't find the method.
This is what is driving me crazy. I really don't see any reason why
this does not work.

What *exactly* did you do when you "put it outside the DataContext"?
Yes I need paging and that was why I am return the tags as a
Collection.

Then that part is fine.
 
S

shapper

But did you update ObjectDataSource1 to point at the new type (or
wherever you put it) at the same time? If not, it's no wonder that it
couldn't find the method.


What *exactly* did you do when you "put it outside the DataContext"?


Then that part is fine.

Hi,

So LabDataContext is a Linq To SQL classes that contains 3 tables:
Tags, Articles and ArticlesTags.

Tags > TagId, Text
Articles > ArticleId, Body
ArticlesTags > TagId, ArticleId

I want to feed the ListView with a Collection that has 3 columns:
TagId, Text and IsActive

So I have 3 options:

1. Use only LabDataContext
TypeName = "LabDataContext"
Place GetTags, DeleteTag, inside the LabDataContext class

2. Create 1 extra class, for example, TagsLayer
TypeName = "TagsLayer"
Place GetTags, DeleteTag, inside the TagsLayer class.

3. Create 2 extra classes, for example, TagsLayer and TagsComponent
TypeName = "TagsLayer"
Place GetTags, DeleteTag, inside the TagsLayer class.
TagsComponent would be a class with 3 properties: TagId, Text and
Active

Is this the idea?
What option should I use?
I think my code problem was a miss understanding of how
ObjectDataSource work.

Thanks,
Miguel
 
J

Jon Skeet [C# MVP]

Is this the idea?
What option should I use?
I think my code problem was a miss understanding of how
ObjectDataSource work.

Well, I don't really see the point of object 3 - but option 2 would be
okay. Then again, why not just use a LINQ to SQL data source in the
first place? What additional functionality do you require?
 
S

shapper

Well, I don't really see the point of object 3 - but option 2 would be
okay. Then again, why not just use a LINQ to SQL data source in the
first place? What additional functionality do you require?

I was trying LinqToSQL Data source for 2 weeks. But I found a few
problems ...
For example, if you use a custom shape selecting you will not be able
to Edit or Delete records. Am I wrong?

"One feature that will not work with custom shapes/projections,
though, is inline editing support. This is because we are doing a
custom projection in our Selecting event, and so the LinqDataSource
has no way to safely know how to update an underlying entity object.
If we want to add editing support to the GridView with a custom shaped
type, we'd want to either move to using an ObjectDataSource control
(where we could supply a custom Update method method to handle the
updates), or have the user navigate to a new page when performing
updates - and display a DetailsView or FormView control that was bound
to a Product entity for editing (and not try and do inline editing
with the grid)."

I read it here:
http://weblogs.asp.net/scottgu/arch...ith-the-lt-asp-linqdatasource-gt-control.aspx

So because I have the Active field I will not be able to edit the
other fields.

One problem I know I will have is when I edit an Article I will want
to edit its tags.
So on Edit mode I will display 3 fields: ArticleTitle, ArticleBody and
ArticleTags.

ArticleTags will be a list of words separated by commas.
On updating I will split the string and add a record for each one in
ArticlesTags.

This is my problem. I am not sure if using a simple LinqDataSource
will be enough.

My other option would be creating all code in ListView events but I
think using an ObjectDataSource would be better.

What do you think?

Thanks,
Miguel
 
J

Jon Skeet [C# MVP]

shapper said:
I was trying LinqToSQL Data source for 2 weeks. But I found a few
problems ...
For example, if you use a custom shape selecting you will not be able
to Edit or Delete records. Am I wrong?

Wouldn't like to say, to be honest - I'm not an ASP.NET expert. That's
why I suggested asking in an ASP.NET group :)
"One feature that will not work with custom shapes/projections,
though, is inline editing support. This is because we are doing a
custom projection in our Selecting event, and so the LinqDataSource
has no way to safely know how to update an underlying entity object.
If we want to add editing support to the GridView with a custom shaped
type, we'd want to either move to using an ObjectDataSource control
(where we could supply a custom Update method method to handle the
updates), or have the user navigate to a new page when performing
updates - and display a DetailsView or FormView control that was bound
to a Product entity for editing (and not try and do inline editing
with the grid)."

I read it here:
http://weblogs.asp.net/scottgu/archive/2007/09/07/linq-to-sql-part-9
-using-a-custom-linq-expression-with-the-lt-asp-linqdatasource-gt-
control.aspx

So because I have the Active field I will not be able to edit the
other fields.

Fair enough.

Personally I don't tend to like using some of the built-in stuff with
ASP.NET anyway - feels too much like magic which screws up as soon as
you try to do anything just a *teeny* bit out of the norm. I guess
you're finding that out too :)
One problem I know I will have is when I edit an Article I will want
to edit its tags.
So on Edit mode I will display 3 fields: ArticleTitle, ArticleBody and
ArticleTags.

ArticleTags will be a list of words separated by commas.
On updating I will split the string and add a record for each one in
ArticlesTags.

This is my problem. I am not sure if using a simple LinqDataSource
will be enough.

Sounds like it might not be.
My other option would be creating all code in ListView events but I
think using an ObjectDataSource would be better.

What do you think?

An ObjectDataSource certainly sounds like a good compromise - and using
LINQ to SQL internally, it's not like it's going to be hard to write.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top