Linq to SQL Foreign Keys & Collections - linq-to-sql

I'm a still trying to wrap myself around LINQ to SQL and foreign key relationships.
I have a table called "Parent" and another called "Children". I have a OneToMany relationship, where a Parent can have multiple Children. My DBML looks something like:
<Table Name="" Member="Parents">
<Type Name="Parent">
<Column Member="ParentID" Type="System.String" IsPrimaryKey="true" CanBeNull="false" />
<Column Member="ChildID" Type="System.String" CanBeNull="false" />
<Association Name="Parent_Child" Member="Childs" ThisKey="ParentID" OtherKey="ParentID" Type="Child" />
</Type>
</Table>
<Table Name="" Member="Childs">
<Type Name="Child">
<Column Member="ChildID" Type="System.String" IsPrimaryKey="true" CanBeNull="false" />
<Column Member="ParentID" Type="System.String" CanBeNull="false" />
<Association Name="Parent_Child" Member="Parent" ThisKey="ParentID" OtherKey="ParentID" Type="Parent" IsForeignKey="true" />
</Type>
</Table>
In my code, I would like do to something like:
// parent has already been loaded from the datacontext
parent.Childs = <some collection of children>
db.SubmitChanges();
But when I do that I get the following error:
A member defining the identity of the object cannot be changed.
Consider adding a new object with new identity and deleting the existing one instead.
Can anyone tell me how to properly accomplish this?

this is actually the error of datacontext,i think u have multiple instance of datacontext..
well u can not add any entity in datacontext witch is already fetched through another instance of datacontext...
even u can so it by setting datacontext.objecttrackingenabled to false and then u can add it to another data context then it will work for sure....

Related

Service Builder Liferay Relationships

I have "Storage" portlet:
I can click "Add Book":
But I need to have opportunity to add author's name to my book. So I created new project, new Service Builder with new entity "author", and now I can add author too. But how can I make dropdown menu with existing authors when I click "add book"? How can I bind that field with new table - "author"?
You don't need to create another project for the author, in the same service builder as the book entity add author entity and add reference to another table that will hold the primary key's of book and author.
service.xml could be:
<service-builder package-path="com.myproject.db">
<author>SO</author>
<namespace>myp</namespace>
<entity name="Book" local-service="true" remote-service="true" cache-enabled="false">
<column name="bookId" type="long" primary="true" />
<column name="name" type="String" />
<column name="description" type="String" />
<column name="price" type="long" />
<column name="author" type="Collection" entity="Author" mapping-table="Author_Books"/>
</entity>
<entity name="Author" local-service="true" remote-service="true" cache-enabled="false">
<column name="authorId" type="long" primary="true" />
<column name="authorName" type="String" />
<column name="books" type="Collection" entity="Book" mapping-table="Author_Books" />
</entity>
</service-builder>
And when you deploy this portlet it will create another table myp_Author_Books that will have composite key of authorId and bookId.
Than in your rendering method of book form add
List<Author> authorList=AuthorLocalServiceUtil.getAuthor(0, AuthorLocalServiceUtil.getAuthorCount());
renderRequest.addAttribute("listAuthor",authorList )
and use this attribute in jsp with c:forEach and aui:select to create your dropdown, smth like:
<aui:select name="author" label="Author Name">
<c:forEach var="currAuthor" items="${listAuthor}">
<aui:option value="${currAuthor.authorId}" label=" ${student.authorName}"></aui:option>
</c:forEach>
</aui:select>

Multiple one-to-many relationships to same entity type and table?

I have an interesting use-case where I'd like Hibernate to manage multiple one-to-many relationships to the same entity type.
For example: BookShelf fictionBooks relationship to Book(s), but also BookShelf nonFictionBooks mapped to Book(s). The Hibernate mapping would look something like this:
<class name="com.example.BookStore" table="BOOK_SHELF">
<id name="id" type="long" column="bookShelfId">
<generator class="native" />
</id>
<set name="fictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
<set name="nonFictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
</class>
<class name="com.example.Book" table="SHELF_BOOK">
<id name="id" type="long" column="shelfBookId">
<generator class="native" />
</id>
<property name="name" not-null="true" unique="true"/>
</class>
Is there a way for the relationship owner BookShelf to specify some discriminator value which could be used to differentiate between Fiction and Non-Fiction books? If possible, the discriminator would be stored as an additional column in SHELF_BOOK table and Hibernate would automatically filter on that.
Is there a way to do this without resorting to either a many-to-many association or extending the Book entity with a Table per class strategy?
Ideally you should have a "type" or "flag" column in SHELF_BOOK table indicating the book is fiction or non-fiction.
Suppose you have added this "type" column, then I think you could specify a filter statement in the set:
<set name="fictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<filter name="myfilter" condition=":type = 'FICTION'"/>
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
You can refer to http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters
From what you posted, I can say that in order to achieve what you wanted you need to modify your relationship owner BookShelf to only store reference to Book and add the property, say bookType, to Book entity.
<class name="com.example.BookStore" table="BOOK_SHELF">
<id name="id" type="long" column="bookShelfId">
<generator class="native" />
</id>
<set name="books" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
</class>
<class name="com.example.Book" table="SHELF_BOOK">
<id name="id" type="long" column="shelfBookId">
<generator class="native" />
</id>
<property name="name" not-null="true" unique="true"/>
<property name="bookType" not-null="true"/>
</class>
There is no other(except ManytoMany) way by which you can find out the type of book by looking into BookShelf entity. You can also use Single Table Strategy which will automatically add the discriminator to the inserted values but in order to do that you need to create two separate classes for FictionalBook and NonFictionalBook .

FuzzyLookup in BIML

I'm trying to do the following in BIML:
I'm at a bit of a loss on how to do this in BIML. Here is what I've tried:
<FuzzyLookup
Name="Fuzzy Lookup"
ConnectionName="WO7"
Exhaustive="true"
AutoPassThroughInputColumns="true"
>
<ExternalReferenceTableInput Table="map.AgencyWO7" />
<Inputs>
<Column SourceColumn="AgencyName" TargetColumn="AgencyName" />
</Inputs>
<Outputs>
<Column SourceColumn="AgencyId" TargetColumn="AgencyIdWO7" />
<Column SourceColumn="AgencyName" TargetColumn="AgencyNameWO7" />
</Outputs>
The result is the following error:
(-1,-1) : Error 5 : The input column for the
Fuzzy Lookup Fuzzy Lookup references external column that cannot be found in the reference table. Verify that the
input mapping references a valid column in the reference table.
Property TargetColumn. EmitSsis. There were errors during compilation.
See compiler output for more information.
I think you are maybe missing a reference to the previous transform which is effectively the joining arrow, had you been using SSDT.
Also the format I use to set passthrough = true is on a per column basis.
<FuzzyLookup Name="Fuzzy Lookup" MatchIndexName="" ConnectionName="WO7">
<InputPath OutputPathName="[Previous Transform Name].Output" />
<ExternalReferenceTableInput Table="map.AgencyWO7" />
<Inputs>
<Column MinSimilarity="85" MatchTypeExact="true" PassThrough="true" SourceColumn="AgencyName" TargetColumn="AgencyName" />
</Inputs>
<Outputs>
<Column SourceColumn="AgencyId" TargetColumn="AgencyIdWO7" />
<Column SourceColumn="AgencyName" TargetColumn="AgencyNameWO7" />
</Outputs>
</FuzzyLookup>
Try the above code, and if all else fails you can design the fuzzy look up in SSDT and then import it into biml using Mist/BimlStudio which is pretty reliable.
https://varigence.com/Mist
Cheers

EF4: ObjectContext inconsistent when inserting into a view with triggers

I get an Invalid Operation Exception when inserting records in a View that uses “Instead of” triggers in SQL Server with ADO.NET Entity Framework 4.
The error message says:
{"The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: The key-value pairs that define an EntityKey cannot be null or empty. Parameter name: record"}
# at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Objects.ObjectContext.SaveChanges()
In this simplified example I created two tables, Contacts and Employers, and one view Contacts_x_Employers which allows me to insert or retrieve rows into/from these two tables at once. The Tables only have a Name and an ID attributes and the view is based on a join of both:
CREATE VIEW [dbo].[Contacts_x_Employers]
AS
SELECT dbo.Contacts.ContactName, dbo.Employers.EmployerName
FROM dbo.Contacts INNER JOIN dbo.Employers
ON dbo.Contacts.EmployerID = dbo.Employers.EmployerID
And has this trigger:
Create TRIGGER C_x_E_Inserts
ON Contacts_x_Employers
INSTEAD of INSERT
AS
BEGIN
SET NOCOUNT ON;
insert into Employers (EmployerName)
select i.EmployerName
from inserted i
where not i.EmployerName in
(select EmployerName from Employers)
insert into Contacts (ContactName, EmployerID)
select i.ContactName, e.EmployerID
from inserted i inner join employers e
on i.EmployerName = e.EmployerName;
END
GO
The .NET Code follows:
using (var Context = new TriggersTestEntities())
{
Contacts_x_Employers CE1 = new Contacts_x_Employers();
CE1.ContactName = "J";
CE1.EmployerName = "T";
Contacts_x_Employers CE2 = new Contacts_x_Employers();
CE1.ContactName = "W";
CE1.EmployerName = "C";
Context.Contacts_x_Employers.AddObject(CE1);
Context.Contacts_x_Employers.AddObject(CE2);
Context.SaveChanges(); // line with error
}
 
SSDL and CSDL (the view nodes):
<EntityType Name="Contacts_x_Employers">
<Key>
<PropertyRef Name="ContactName" />
<PropertyRef Name="EmployerName" />
</Key>
<Property Name="ContactName" Type="varchar" Nullable="false" MaxLength="50" />
<Property Name="EmployerName" Type="varchar" Nullable="false" MaxLength="50" />
</EntityType>
<EntityType Name="Contacts_x_Employers">
<Key>
<PropertyRef Name="ContactName" />
<PropertyRef Name="EmployerName" />
</Key>
<Property Name="ContactName" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
<Property Name="EmployerName" Type="String" Nullable="false" MaxLength="50" Unicode="false" FixedLength="false" />
</EntityType>
The Visual Studio solution and the SQL Scripts to re-create the whole application can be found in the TestViewTrggers.zip at ftp://JulioSantos.com/files/TriggerBug/.
I appreciate any assistance that can be provided. I already spent days working on this problem.
I stumbled on the same problem when I tried to insert a row in a view with "instead of insert" and "instead of update" triggers.
I think I found a solution: when visual studio's wizard drop your view in your model, it add a StoreGeneratedPattern="Identity" on some properties (probably the keys of your entity).
When generating requests on a regular table, this property tells entity framework to expect an ID in return, so it append a select scope_identity() at the end of the insert.
Now with updatable views the scope_identity is screwed because the insert happen in another scope and it returns null, so the insert fail.
If you remove this StoreGeneratedPattern="Identity" from the model, entity framework doesn't append select scope_identity() and the insert is working fine.
I hope this solve your problem and that it doesn't come too late.
Cheers
More details here : http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/9fe80b08-0b67-4163-9cb0-41dee5115148/

Linq To SQL : Error "Database node not found"

I am attempting to experiment with linq to sql using this site as a guide.
When running a test I keep getting an error parsing the mapping file I created. The error:
System.Xml.Schema.XmlSchemaException : Database node not found. Is the mapping namespace (http://schemas.microsoft.com/linqtosql/mapping/2007) correctly specified?
Here is the mapping file:
<?xml version="1.0" encoding="utf-8"?>
<Database Name="Test" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007">
<Table Name="dbo.Categories" Member="Category">
<Type Name="Category">
<Column Name="ID" Member="ID" Storage="id" DbType="Char(32) NOT NULL" CanBeNull="false" IsPrimaryKey="true" />
<Column Name="ParentID" Member="ParentID" Storage="parentID" DbType="Char(32)" />
<Column Name="Name" Member="Name" Storage="name" DbType="VarChar(50) NOT NULL" CanBeNull="false" />
</Type>
</Table>
</Database>
Can anyone point me in the right direction?
Figured it out!
the line:
<Table Name="dbo.Categories" Member="Category">
Needed changed to:
<Table Name="dbo.Categories" Member="Categories">
and now its working.