I have a custom entity with a one to many relationship (reference, non parental) defined in Dynamics. I'm using CRMService. I've published my changes and updated the webservice reference in my project.
How do I access this relationship in my code? How do you use CRMService code to reference a relationship?
I've found some code for many-to-many and understand that is difficult, but what about one to many?
Thanks!
Each one to many relationship has two important bits:
A name - this isnt used as often but for example contact has a relationship to account which represents the primary contact for the account, the name of this is "account_primary_contact".
A field on the many entity (the foreign key), in the case of the primary contact this is "primarycontactid".
Theres three main things things you can do with a one to many relationship (note, I'm using the late bound entities in my examples here, I will be using the primary contact relationship in my snippets).
1. Create a link between two records
Basically you just populate the foreign key with the Id of the thing you want to link to.
//Create a contact
Guid contactId = service.Create(new DynamicEntity("contact"));
//Create a lookup which we will use to link the contact and account
Lookup lookup = new Lookup();
lookup.Value = contactId;
lookup.type = "contact";
//Create an account which is linked to the contact record
DynamicEntity account = new DynamicEntity("account");
account["name"] = "Test Account";
account["primarycontactid"] = lookup;
Guid accountId = service.Create(account);
2. Find out what records are linked by those relationships
So this is a case of creating a QueryExpression which either uses LinkEntities:
LinkEntity link = new LinkEntity();
link.LinkFromEntityName = "contact";
link.LinkFromAttributeName = "contactid";
link.LinkToEntityName = "account";
link.LinkToAttributeName = "primarycontactid";
Or a ConditionExpression which filters the related records to those linked to your primary record.
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "primarycontactid";
condition.Operator = ConditionOperator.Equal;
condition.Values = new string [] { contactId.ToString() };
Full examples on the MSDN.
3. Break the link between two records
So this is achieved by setting the foreign key to null.
DynamicEntity account = new DynamicEntity("account");
account["primarycontactid"] = null;
service.Update(account);
Related
Let's say I have a Company table and a Division table. Each Division has a Foreign key to a company so each company can have many Division children.
If I grab a Company object with Linq-to-sql I have a access to it's Divisions property, a entity set of Division objects. If I add a new Division object to it and call SubmitChanges() won't it automatically go into the Division table or am I forced to call InsertOnSubmit?
There are multiple ways to insert objects into the database with LINQ to SQL. For instance:
db.Divisions.InsertOnSubmit(new Division()
{
Company = db.Company.Single(c => c.Id == 1),
// other properties
});
db.SubmitChanges();
Or:
var company = db.Company.Single(c => c.Id == 1);
company.Divisions.Add(new Division()
{
// other properties
});
db.SubmitChanges();
As you can see, you can use the InsertOnSubmit of the Table<Division> Divisions property on the data context, but you can also use the Add method of the EntitySet<Division> Divisions property on the Company entity. They both do -about- the same. Nice about the latter approach is that you don't need to 'link' the company to the new division, because LINQ to SQL can figure that out for you.
I hope this answers your question.
I am implementing the asp.net MVC web application, where i am using the Linq to Sql to manipulate the data in database. but in my one of action, i want to insert multiple table entries which are depends upon each other by referring previous insertion Id's. So i just wnat to know how to handle the transaction, like begin transaction, commit,rollback and all like in ADO.net. how to manage this. what if one of insertion get crashed in the middle of manipulation?
Note:- I am not using the Stored procedures here. I am using Lambda expressions and methods. Also these are use in different manager classes.
Example:
For Create Subject - used method in SubjectManager class to insert subject infor, that returns subject Id. within this subjectid i am inserting the let say its chapters with another method in manager class as ChapterManager. which again returns the ChapterId, on base of this chapeter Id , inserting the Topics of chapter. that again uses Topic manager same like above.in each manger class i am creating dataContext object for the same. and I am controlling all this within a single action in my controller. but worrying about the transaction management. how I can use here ?
The DataContext already includes an embedded transaction object. For example, let's say you are placing a new order for a customer. You can set up your model so that the following code updates both the Customer AND Order table with a single SubmitChanges. As long as a foreign key relationship exists between the two tables, the embedded transaction object handles both the Customer update and the Order insert in the same transaction. Using a TransactionScope object to encase a single DataContext is redundant:
using (DataContext dc = new DataContext())
{
Order order = new Order();
order.ProductID = 283564;
order.Quantity = 7;
order.OrderDate = DateTime.Now;
Customer customer = dc.Customers.Single(c => c.CustomerID == 6);
customer.LastUpdate = order.OrderDate;
customer.Orders.Add(order);
dc.SubmitChanges();
}
using(TransactionScope scope = new TransactionScope())
{
using(DataContext ctx = new MyDataContext())
{
ctx.Subject.Add(subject);
Chapter chapter = new Chapter();
chapter.SubjectId = subject.Id;
ctx.SubmitChanges();
ctx.Chapter.Add(chapter);
ctx.SubmitChanges();
scope.Complete() // if it all worked out
}
}
From the System.Transactions namespace I believe.
How to retrieve identity ID when inserting a row in the db using linq?
If you've set the properties of that "ID" row to "Auto-Generated Value" = true and "Auto-Sync" to "OnInsert"
..... just read it after you've saved the changes using .SubmitChanges(). No special tricks or anything needed....
So in case of the NerdDinner sample:
using(NerdDinnerContext ctx = new NerdDinnerContext())
{
Dinner upcoming = new Dinner();
// set all properties for the dinner
upcoming.EventDate = DateTime.Today.AddDays(30);
ctx.Dinners.InsertOnSubmit(upcoming);
ctx.SubmitChanges();
int newDinnerID = upcoming.DinnerID;
}
Now "newDinnerID" should contain the newly added IDENTITY.
Marc
LINQ to SQL should automatically retrieve the identity of the inserted object, and update the field you mapped to the primary key accordingly - so long as the mapped PK property is marked as [Column(IsDbGenerated=true)].
I am hoping you can help. I am developing a tiered website using Linq to Sql. I created a new class(or object) in DBML designer called memberState. This object is not an actual table in the database. I have this method in my middle layer:
public override IEnumerable(memberState) GetMembersByState(string #state)
{
using (BulletinWizardDataContext context = DataContext)
{
IEnumerable(memberState) mems = (from m in context.Members
join ma in context.MemberAddresses
on m.UserId equals ma.UserId
join s in context.States
on ma.StateId equals s.StateId
where s.StateName == #state
select new memberState
{
userId = m.UserID,
firstName = m.FirstName,
middleInitial = m.MiddleInitial,
lastName = m.LastName,
createDate = m.CreateDate,
modifyDate = m.ModifyDate
}).ToArray(memberState)();
return mems;
}
}
The tables in my joins (Members, States, and MemberAddresses are actual tables in my Database). I created the object memberStates so I could use it in the query above (notice the Select New memberState. When the data is updated on the web page how do I persist the changes back to the Member Table? My Member Table consists of the following columns: UserId, FirstName, MiddleInitial, LastName, CreateDate, ModifyDate. I am not sure how save the changes back to the database.
Thanks,
If I remember correctly, you can create a view from the different tables (Members, States, and MemberAddresses) and add that to the data context. Then any modifications to data in the view object can be saved, and linq to sql will handle the commit correctly as long as all the relationships are clearly setup/defined in both the database and in the data context.
If you have a Member table, the dbml will most likely contain a Member class. To update a member in the database, you will have to create a new Member object, and the Attach it to the BulletinWizardDataContext.Members collection. Something similar to the following code should the trick (I have not tested the code):
using (BulletinWizardDataContext context = DataContext)
{
Member m = new Member() { UserId = userId };
context.Members.Attach(m);
m.FirstName = firstName;
// Set other properties
context.SubmitChanges();
}
Attach must be called before setting the properties. Also, Linq2Sql has some issues with Attach in the case where the properties of your object are set to default values (i.e. 0 for numeric values, false for booleans, null for string etc.). In this case Attach will not generate the correct SQL.
var m = myContext.Members.Single(m=> m.UserID == myMemState.userID);
m.FirstName = myMemState.firstName;
m.MiddleInitial = myMemState.middleInitial;
...
That would be the quick way. It does an additional roundtrip to the db, but will work well. If that's an issue for you, then do Attach like Jakob suggested. For that you have to have to do some extra steps, like reviewing the configuration for optimistic updates and make sure you have the original fields when doing the attach.
I'm trying to copy all object attibutes to another object, fox example:
Person p1 = new Person();
p1.name = "John";
p1.sex = 'M';
Person p2 = new Person();
p2 = Util.Clone(p1);
The problem is that Person entity has an identity PK 'codPerson' and I don't want to copy this PK. Is there a way to clone/copy an object, but don't copy its PK attribute??
Thanks!!!
Perhaps you might consider the following:
Ensure Util.Clone(Person p) doesn't
copy the codPerson attribute
Clear the attribute after the Clone method
is called
Create a new Person object while specifically initializing specific properties.
At the most basic level you can't - given an arbitrary object o (and the question implies you're looking for generic solutions) you have no way to determine which field is a primary key.
So you step up a level - by adding some constraints i.e. that you will inform your tools what the primary key field is (or fields are) and hence enable use of a generic method.
So, you could explicitly specify the PK field (name) to the code that does the clone (I assume that you're using reflection to avoid explicitly copying all the fields). You could identify the PK by using annotation of some sort on the classes being cloned and have the clone code exclude properties with the relevant annotation (the annotation implies that the field won't be cloned). There may be other methods
You mention Linq - are you using a specific bit of Linq ?
Beyond that there's not a lot one can suggest without more details - ah but the question is tagged with Linq to SQL (which I missed) ok...
There's nothing obvious in a Linq to SQL class that will help - nor with the "table" but a quick look at the generated code in .designer.cs shows that a key field has annotations similar to the following (taken from a set of classes I have to hand):
[Column(Storage="_ID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
Therefore when you're do your reflection on the class to enumerate the properties to copy you'll want to look for the column and the "IsPrimaryKey" property within the column - unfortunately the details of how to do that are some distance outside my comfort zone!
You could manually set the properties on the new object to be equal to the old one.
For example:
Person p2 = new Person {
Name = p1.Name,
Gender = p1.Gender,
//...
};
you can use .net Reflection.
//using System.Reflection;
var yourEntity = new Person {Name = "Green", Surname= "White"};
var cloneEntity = new Person();
var allPi = typeof(Person).GetProperties();
foreach (var pi in allPi)
{
if (pi.Name != "codPerson" && pi != null && pi.CanWrite)
pi.SetValue(cloneEntity , pi.GetValue(yourEntity , null));
}