Linq to Entities - Reference EntityKey - linq

Now that I have built a database.
Visual Studio 2008 SP1’s ADO.NET Entity Framework has generated an Entity Model like this:
http://img835.imageshack.us/img835/1810/carease15test1ef.png
I have created a method as follow:
private void buttonAddPatient_Click(object sender, EventArgs e)
{
using (carease15test1Entities context = new carease15test1Entities())
{
long bnumber = Convert.ToInt32(textBoxToBed.Text);
long rnumber = Convert.ToInt32(textBoxOfRoom.Text);
long bid = (from b in context.bed
where b.bnumber == bnumber
select b.bid).First();
long rid = (from r in context.room
where r.rnumber == rnumber
select r.rid).First();
// Create a new bed, and input its details.
patient p = new patient();
p.pname = textBoxPatient.Text;
p.Bed_bid = bid;
p.bedReference.EntityKey = new EntityKey("carease15test1Entities.bed", "bid", bid);
p.Bed_Room_rid = rid;
p.bed.roomReference.EntityKey = new EntityKey("carease15test1Entities.room", "rid", rid);
context.AddTopatient(p);
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException ex)
{
// Resolve the concurrency conflict by refreshing the // object context before re-saving changes.
context.Refresh(System.Data.Objects.RefreshMode.ClientWins, p);
// Save changes.
context.SaveChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Everything works perfectly except for
p.bed.roomReference.EntityKey = new EntityKey("carease15test1Entities.room", "rid", rid);
It turns out a NullRefenceException saying “Object reference not set to an instance of an object.”
Here is my project files.
http://www.mediafire.com/?w3rjjbxbxw6wacv
Could anyone give me some help?
Thank you so much.

You should do
p.bedReference.Load()
So that contents of p.bed are loaded.
P.S.
If you can upgrade to .NET 4.0 it will be done automatically for you.

Related

Calling Dynamics Web API with Entity metadata early binding

I would like to consume my organizations dynamics oData endpoint but with early bound classes. However, there are a lot of early bound tools out there and I wanted to know which one provides the best developer experience/least resistance?
For example, there is this one:
https://github.com/daryllabar/DLaB.Xrm.XrmToolBoxTools
https://github.com/yagasoft/DynamicsCrm-CodeGenerator
and so on. Is there a developer preference/method out there?
Early bound classes are for use with the Organization Service which is a SOAP service. The normal way to generate those classes is using CrmSvcUtil.
OData can be used in Organization Data Service or Web API, but those don't have Early Bound classes.
Further reading: Introducing the Microsoft Dynamics 365 web services
It's not impossible to use with standard SOAP Early bound class. We just have to be creative. If we work just with basic attributes (fields, not relationships, ecc) it seems possible. For example. for create and update, OData will not accept the entire early bounded class, just pass the attibutes:
class Program
{
static void Main(string[] args)
{
string token = System.Threading.Tasks.Task.Run(() => GetToken()).Result;
CRMWebAPI dynamicsWebAPI = new CRMWebAPI("https:/ORG.api.crm4.dynamics.com/api/data/v9.1/",
token);
CRMGetListOptions listOptions = new CRMGetListOptions
{
Select = new string[] { "EntitySetName" },
Filter = "LogicalName eq 'contact'"
};
dynamic entityDefinitions = dynamicsWebAPI.GetList<ExpandoObject>("EntityDefinitions", listOptions).Result;
Contact contact = new Contact
{
FirstName = "Felipe",
LastName = "Test",
MobilePhone = "38421254"
};
dynamic ret = System.Threading.Tasks.Task.Run(async () => await dynamicsWebAPI.Create(entityDefinitions.List[0].EntitySetName, KeyPairValueToObject(contact.Attributes))).Result;
}
public static async Task<string> GetToken()
{
string api = "https://ORG.api.crm4.dynamics.com/";
ClientCredential credential = new ClientCredential("CLIENT_ID", "CLIENT_SECRET");
AuthenticationContext authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/commom/oauth2/authorize");
return authenticationContext.AcquireTokenAsync(api, credential).Result.AccessToken;
}
public static object KeyPairValueToObject(AttributeCollection keyValuePairs)
{
dynamic expando = new ExpandoObject();
var obj = expando as IDictionary<string, object>;
foreach (var keyValuePair in keyValuePairs)
obj.Add(keyValuePair.Key, keyValuePair.Value);
return obj;
}
}
It's a simple approach and I didn't went further.
Maybe we have to serealize other objects as OptionSets, DateTime (pass just the string) and EntityReferences but this simple test worked fine to me. I'm using Xrm.Tools.WebAPI and Microsoft.IdentityModel.Clients.ActiveDirectory. Maybe it's a way.
[Edit]
And so I decided to go and created a not well tested method to cast the attributes. Problems: We have to follow OData statments to use the API. To update/create an entity reference we can use this to reference https://www.inogic.com/blog/2016/02/set-values-of-all-data-types-using-web-api-in-dynamics-crm/
So
//To EntityReference
entityToUpdateOrCreate["FIELD_SCHEMA_NAME#odata.bind"] = "/ENTITY_SET_NAME(GUID)";
So, it's the Schema name, not field name. If you use CamelCase when set you fields name you'll have a problem where. We can resolve that with a (to that cute) code
public static object EntityToObject<T>(T entity) where T : Entity
{
dynamic expando = new ExpandoObject();
var obj = expando as IDictionary<string, object>;
foreach (var keyValuePair in entity.Attributes)
{
obj.Add(GetFieldName(entity, keyValuePair), CastEntityAttibutesValueOnDynamicObject(keyValuePair.Value));
}
return obj;
}
public static object CastEntityAttibutesValueOnDynamicObject(object attributeValue)
{
if (attributeValue.GetType().Name == "EntityReference")
{
CRMGetListOptions listOptions = new CRMGetListOptions
{
Select = new string[] { "EntitySetName" },
Filter = $"LogicalName eq '{((EntityReference)attributeValue).LogicalName}'"
};
dynamic entitySetName = dynamicsWebAPI.GetList<ExpandoObject>("EntityDefinitions", listOptions).Result.List[0];
return $"/{entitySetName.EntitySetName}({((EntityReference)attributeValue).Id})";
}
else if (attributeValue.GetType().Name == "OptionSetValue")
{
return ((OptionSetValue)attributeValue).Value;
}
else if (attributeValue.GetType().Name == "DateTime")
{
return ((DateTime)attributeValue).ToString("yyyy-MM-dd");
}
else if (attributeValue.GetType().Name == "Money")
{
return ((Money)attributeValue).Value;
}
else if (attributeValue.GetType().Name == "AliasedValue")
{
return CastEntityAttibutesValueOnDynamicObject(((AliasedValue)attributeValue).Value);
}
else
{
return attributeValue;
}
}
public static string GetFieldName<T>(T entity, KeyValuePair<string, object> keyValuePair) where T : Entity
{
switch (keyValuePair.Value.GetType().Name)
{
case "EntityReference":
var entityNameList = System.Threading.Tasks.Task.Run(async () => await dynamicsWebAPI.GetEntityDisplayNameList()).Result;
var firstEntity = entityNameList.Where(x => x.LogicalName == entity.LogicalName).FirstOrDefault();
var attrNameList = System.Threading.Tasks.Task.Run(async () => await dynamicsWebAPI.GetAttributeDisplayNameList(firstEntity.MetadataId)).Result;
return attrNameList.Where(x => x.LogicalName == keyValuePair.Key).Single().SchemaName + "#odata.bind";
case "ActivityParty":
throw new NotImplementedException(); //TODO
default:
return keyValuePair.Key;
}
}
Please, note that this approach do not seems fast or good in anyway. It's better if you have all this values as static so we can save some fetches
[Edit 2]
I just found on XRMToolBox a plugin called "Early bound generator for Web API" and it seems to be the best option. Maybe you should give it a try if you're still curious about that. I guess its the best approach.
The final code is this:
static void Main(string[] args)
{
string token = Task.Run(() => GetToken()).Result;
dynamicsWebAPI = new CRMWebAPI("https://ORG.api.crm4.dynamics.com/api/data/v9.1/",
token);
Contact contact = new Contact
{
FirstName = "Felipe",
LastName = "Test",
MobilePhone = "38421254",
new_Salutation = new EntityReference(new_salutation.EntitySetName, new Guid("{BFA27540-7BB9-E611-80EE-FC15B4281C8C}")),
BirthDate = new DateTime(1993, 04, 14),
};
dynamic ret = Task.Run(async () => await dynamicsWebAPI.Create(Contact.EntitySetName, contact.ToExpandoObject())).Result;
Contact createdContact = dynamicsWebAPI.Get<Contact>(Contact.EntitySetName, ret, new CRMGetListOptions
{
Select = new string[] { "*" }
}).Result;
}
and you have to change the ToExpandoObject on Entity.cs class (generated by the plugin)
public ExpandoObject ToExpandoObject()
{
dynamic expando = new ExpandoObject();
var expandoObject = expando as IDictionary<string, object>;
foreach (var attributes in Attributes)
{
if (attributes.Key == GetIdAttribute())
{
continue;
}
var value = attributes.Value;
var key = attributes.Key;
if (value is EntityReference entityReference)
{
value = $"/{entityReference.EntitySetName}({entityReference.EntityId})";
}
else
{
key = key.ToLower();
if (value is DateTime dateTimeValue)
{
var propertyForAttribute = GetPublicInstanceProperties().FirstOrDefault(x =>
x.Name.Equals(key, StringComparison.InvariantCultureIgnoreCase));
if (propertyForAttribute != null)
{
var onlyDateAttr = propertyForAttribute.GetCustomAttribute<OnlyDateAttribute>();
if (onlyDateAttr != null)
{
value = dateTimeValue.ToString(OnlyDateAttribute.Format);
}
}
}
}
expandoObject.Add(key, value);
}
return (ExpandoObject)expandoObject;
}
Links:
https://github.com/davidyack/Xrm.Tools.CRMWebAPI
https://www.xrmtoolbox.com/plugins/crm.webApi.earlyBoundGenerator/
We currently use XrmToolkit which has it's own version of early binding called ProxyClasses but will allow you to generate early binding using the CRM Service Utility (CrmSvcUtil). It does a lot more than just early binding which is why we use it on all of our projects but the early binding features alone would have me sold on it. in order to regenerate an entity definition all you do is right click the cs file in visual studio and select regenerate and it is done in a few seconds.
For my first 3 years of CRM development I used the XrmToolbox "Early Bound Generator" plugin which is really helpful as well.

Linq update Trouble

I want to update my Azure database using linq in my xamarin.forms project
below is the initalise and sync methods that connect to the database. These work successfully. My problem is that I want to update a record is the database. Any suggestions are welcome.
MobileServiceClient client = null;
IMobileServiceSyncTable<Shop> ShopTable2;
bool isInitialised;
public async Task Initialize()
{
if (isInitialised)
{
return;
}
this.client = new MobileServiceClient("link to database");
MobileServiceClient client = new MobileServiceClient("link to databse");
const string path = "user.db";
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<Shop>();
await this.client.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
ShopTable2= this.client.GetSyncTable<Shop>();
isInitialised = true;
}
sync method
public async Task Sync()
{
try
{
await shopTable2.PullAsync("allusers3", shopTable2.CreateQuery());
await client.SyncContext.PushAsync();
}
catch (Exception ex)
{
Debug.WriteLine("Unable to sync " + ex);
}
}
where I want to update the records here:
public async void BuyProducts(string Pname)
{
string productname = Pname;
await Initialize();
await SyncBookings();
List<Shop_TBL> item = await BookingsTable2
.Where(todoItem => todoItem.ProductName == productname)
.ToListAsync();
}
Assuming you are using Entity Framework as your ORM:
Select the entity you want to update.
var book = db.Books.First(b => b.Id == _id);
Change the property:
book.Name = "Something else";
Save the changes:
await db.SaveChangesAsync();
or
db.SaveChanges();
That's how you do an update.

Force tags to update from external event

this is a somewhat exotic question but I will try anyway.
I am writing a Visual Studio 2010 Extension using MEF. At some point in my code, I am required to provide some error glyphs ( like brakepoints ) whenever a document is saved. The problem is that I can't seem to find how to force GetTags of my ITagger to be called without having the user writing anything.
I can catch the document save event but I am missing the "link" between this and somehow getting GetTags method to be called. Any ideas?
Here is some code :
internal class RTextErrorTag : IGlyphTag
{}
class RTextErrorGlyphTagger : ITagger<RTextErrorTag>
{
private IClassifier mClassifier;
private SimpleTagger<ErrorTag> mSquiggleTagger;
private EnvDTE._DTE mMSVSInstance = null;
private List<object> mDTEEvents = new List<object>();
internal RTextErrorGlyphTagger(IClassifier classifier, IErrorProviderFactory squiggleProviderFactory, ITextBuffer buffer, IServiceProvider serviceProvider)
{
this.mClassifier = classifier;
this.mSquiggleTagger = squiggleProviderFactory.GetErrorTagger(buffer);
mMSVSInstance = serviceProvider.GetService(typeof(EnvDTE._DTE)) as EnvDTE._DTE;
var eventHolder = mMSVSInstance.Events.DocumentEvents;
mDTEEvents.Add(eventHolder);
eventHolder.DocumentSaved += new EnvDTE._dispDocumentEvents_DocumentSavedEventHandler(OnDocumentSaved);
}
void OnDocumentSaved(EnvDTE.Document Document)
{
//fire up event to renew glyphs - how to force GetTags method?
var temp = this.TagsChanged;
if (temp != null)
temp(this, new SnapshotSpanEventArgs(new SnapshotSpan() )); //how to foce get
}
IEnumerable<ITagSpan<RTextErrorTag>> ITagger<RTextErrorTag>.GetTags(NormalizedSnapshotSpanCollection spans)
{
foreach (SnapshotSpan span in spans)
{
foreach (var error in this.mSquiggleTagger.GetTaggedSpans(span))
{
yield return new TagSpan<RTextErrorTag>(new SnapshotSpan(span.Start, 1), new RTextErrorTag());
}
}
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged;
}

How to update the userlocation to server when the location was changed in windows phone 7?

I need to update the userlocation to server when the location is changed .Please tell me how to acheive this?
using below method:
void GeoPositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
{
_pushpins.Clear();
var cor = new GeoCoordinate(e.Position.Location.Latitude, e.Position.Location.Longitude);
//Using the current coordinates define the Map center to those coordinates.
map.Center = cor;
_pushpins.Add(new PushpinModel
{
UserId=userId,
Description = "test",
Name = "test",
Location = new GeoCoordinate(e.Position.Location.Latitude,
e.Position.Location.Longitude),
DatetimeAdded = DateTime.Now
});
map.ZoomLevel = 15;
//locationupdate method
locationupdate(e.Position.Location.Latitude,
e.Position.Location.Longitude);
}
private void locationupdate(double lat,double lon)
{
bool isAvailable = NetworkInterface.GetIsNetworkAvailable();
if (isAvailable == true)
{
try
{
WebClient wc = new WebClient();
wc.DownloadStringAsync(
new Uri("http://{ipaddress}/Network/Records/UpdateLocation?userid="+userId+"&latitude="+lat+"&longitude="+lon));
wc.DownloadStringCompleted +=
new DownloadStringCompletedEventHandler(
wc_DownloadStringUpdateCompleted);
}
catch (Exception ex)
{
throw;
}
}
else
{
MessageBox.Show("Network is not available.Please try again later");
}
}
Please tell me the above will update the location whenever user was changed his location?
Separate your goal...
Do you already know how to get the user location?
Use background agents to run taks on the background (if necessary) http://www.silverlightshow.net/items/Windows-Phone-7.5-Use-Background-agents.aspx
Create a webservice to update you're server

Linq to entities in asp.net and generic delete method

I am having trouble creating generic delete method, not even sure if this possible. I have a delete method which will delete record from db based on entity type and row id value (pk),
that works ok but it needs to know the type in advance. In some cases I can only get object
type using Object.GetType() at runtime (like from viewstate) and that is when trouble starts. Here is my method that works when type is known, is there a way to modify it so that it will use Object.GetType() instead of T ?
public void Delete<T>(long Id) where T : class,new()
{
#region PerformaneMonitor
IDbEntities Db=null;
T item=null;
try
{
Db = this.GetDatabase();
item = new T();
Type itemType = item.GetType();
EntityContainer entityContainer = Db.MetadataWorkspace.GetEntityContainer(Db.DefaultContainerName, DataSpace.CSpace);
var entity = entityContainer.BaseEntitySets.First(b => b.ElementType.Name == itemType.Name);
if (entity.ElementType.KeyMembers.Count == 0)
{
throw new Exception("Unable to delete a record witout unique id");
}
string PrimaryKeyName = entity.ElementType.KeyMembers[0].Name;
itemType.GetProperty(PrimaryKeyName).SetValue(item, Id, null);
}
catch (Exception ex)
{
Close(Db);
throw(ex);
}
this.Delete<T>(item, Db);
Close(Db);
#region PerformaneMonitor
}
so I am trying to convert it to Delete(object EntityType,long Id ) but no luck.
Here what it looks like :
public void Delete(object target,long Id)
{
#region PerformaneMonitor
IDbEntities Db = null;
try
{
Db = this.GetDatabase();
Type itemType = (Type)target;
EntityContainer entityContainer = Db.MetadataWorkspace.GetEntityContainer(Db.DefaultContainerName, DataSpace.CSpace);
var entity= entityContainer.BaseEntitySets.First(b => b.ElementType.Name == itemType.Name);
if (entity.ElementType.KeyMembers.Count == 0)
{
throw new Exception("Unable to delete a record witout unique id");
}
string PrimaryKeyName = entity.ElementType.KeyMembers[0].Name;
itemType.GetProperty(PrimaryKeyName).SetValue(target, Id, null);
}
catch (Exception ex)
{
Close(Db);
throw (ex);
}
this.Delete(target, Db);
Close(Db);
//_method_tag_end_
#region PerformaneMonitor
}
I am getting 'Object does not match target type' on
this line:
itemType.GetProperty(PrimaryKeyName).SetValue(target, pkey, null);
the object target is actaul instance of specific type which I do in the calling method from Type of object and using reflection and pass to this function but still I have no idea what type it is at run time.
If someone can help it will be greatly appreciated.
It sounds like you should do something along these lines: (Sorry, can't test to make sure it works as written.)
object o = itemType.GetProperty(PrimaryKeyName);
MethodInfo mi = o.GetType().GetMethod("SetValue");
mi.Invoke(o, new object [] { Id, null });

Resources