I'm trying to create a single instance of a model in my Db using Entity Core. The way I want it to work is, if the entry in the Db does not exist than make one. Instead of writing a getter method to do the work, is it possible to have Entity Core generate me a blank entry to work with and the save back?
I tried using FirstOrDefault to no avail.
Here is some sample code:
using (var context = new SearchTermInformationContext())
{
// this very first line should return me the single instance or create one if it doesnt exist.
var searchTermInfo = context.SearchTermInformation.FirstOrDefault();
searchTermInfo.num_search_terms += numSearchTerms;
searchTermInfo.offset = offset;
searchTermInfo.last_updated += (DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond).ToString();
await context.SaveChangesAsync(ct);
}
FirstOrDefault() grabs the first element of an IEnumerable, and if the sequence is empty it returns the default value for that type. Since an Entity is always going to be a class, the default "value" for any class is null. There is no way to my knowledge to change this behavior. If you want this behavior, you will have to implement it yourself by creating a new instance of your type, filling in the fields, and performing an insert through your context. If you want to get really fancy, you might be able to make an extension method on DbSet<T> to perform an add of a blank instance and return the attached entity without saving changes.
Related
I am creating a web API. I need something like this:
When I updating a document at mongodb, I do not want to update a field (createdAt). I know that I can get a old value of that field and manuelly and then put it updated object but it requires one more unnecessarry request to db. I do not want this. My method is here:
public async Task<bool> UpdateAsync(Customer updatedCustomer)
{
var result = await _mongoService.Customers.ReplaceOneAsync(c => c.Id == updatedCustomer.Id, updatedCustomer);
return result.IsModifiedCountAvailable && result.ModifiedCount>0;
}
Is there any way to exclude one property of my Customer class (createdAt) and left it same everytime. BTW please do not recomend that set all properties update one by one by using "Set" method. Thank you.
I'm not sure if there is a way other than to set the properties one by one, but researching the following may be helpful or suggestive of something new.
In Mongodb you can use some decoration to do like [BsonIgnore] but it will ignore it every time
One alternative would be to load the document you wish to modify, followed by calling BsonDocument.Merge with overwriteExistingElements set to true in order to merge your changes.
I'm developing an application which can deal with a MS-ADLDS-Service.
Currently it is possible to create Directory-Entries and assign values to some properties.
Not a realy exciting task until this:
Im my application it's possible (it should be) to configure which properties of a class (for instance: the CN=Person class) should be assigned with values which are evaluated at runtime in my application.
Long story short:
I want to retrieve all (writeable) properties of a class. Without creating and saving a new CN=Person-Object before.
Currently i use my schemaBinding to get the Directory-classSchema-Entry of the Person-Class (CN=Person) from where i read some property-values (like "AllowedAttributesEffective", "mayContain", "AllowedAttributes") - i get the most properties by this way - but some Properties are missing! For instance the "telephoneNumber"-Property (attributeSchema: CN=Telephone-Number)
Does anybody know how to get these properties of a class? ADSI-Edit does this: when i create a new object with adsi-edit i can assign values to all possible properties before committing the new entry.
thanks a lot for any hint!
(.net code is welcome)
I have found the solution for my task!
Some of these properties are "calculated" and not persistent at the directoryentry.
So its meant to call the RefreshCache() Method and pass the needed property names as an string array.
directoryEntry.RefreshCache(new string[] { "allowedAttributesEffective",
"allowedAttributes",
"systemMayContain",
"systemMustContain" });
After that call, the properties have values....
if (directoryEntry.Properties["systemMayContain"]).Value != null)
{
/// Success
}
I have db4o file created by some App (which I don't have source for) and I need to get all the data from this file.
In all examples I saw in tutorials there were Classes used for retrieving objects but what to do if I don't have these classes?
You can try it with LINQPad and my driver: http://www.gamlor.info/wordpress/2011/03/db4o-driver-for-linqpad/
Otherwise, you can explore the db4o reflection API:
Assuming you have no class, and just want to see everything. Something like this (don't remember the exact API):
IQuery query = container.Query();
IEnumerable allObjects = query.Execute();
foreach(Object item : allObjects){
GenericObject dbObject = (GenericObject)item; // Note: If db4o finds actuall class, it will be the right class, otherwise GenericObject. You may need to do some checks and casts
dbObject.GetGenericClass().GetDeclaredFields(); // Find out fields
object fieldData = dbObject.Get(0); // Get the field at index 0. The GetDeclaredFields() tells you which field is at which index
}
I am using EF 4. I want to add a row to a (message) table, so I declare a new object (newMSG), and populate it. Then I use the message table's method .AddObject(newMSG) to add the new row.
Is the newMSG object now available to "re-use" to add another row? Or do I need to have a new object? Seems like I should be able to re-use the newMSG object, but it's not so easy to test.
You guys'll know right off the bat... Of course, this would apply to any object, I assume. There's nothing special about EF....
Does it matter perhaps if I use the savechanges() method between uses?
You need a new object. There is metadata attached to that newMSG object that ties it to that particular row.
I've got a browser sending up JSON but it only includes the properties of a given model that have been changed. So once the WCF DataContractJsonSerializer does it's work I have an object that will have perhaps only the ID and Description fields populated.
Attaching this to the DbContext as is will result in the description field being updated but all the other fields being set to their types default value in the database. This is because if WCF doesn't see the property specified in the JSON then it'll skip over it, meaning the property in the instance will just use the types default value as per the auto-implemented property.
So this means that I need to decide on which fields have been passed up without having access to the JSON itself. In fact it could be XML on the wire so all I can work from is this partly serialized object.
What seems most logical is to use null as the special value that means this property hasn't been serializd over. So in the constructor of the POCO model I set all the properties to null.
In the Update method I then use this serialized object as a stub. I have to walk each property and if the value isn't set to null then I set it's state to modified. As far as I can tell this is working without any side effects but I'm just not sure that this is the way to do something like this.
One limitation it does add is that the client can no longer intentionally set a property to null as that update would be lost. One way around this is to have a special int value that can be set to represent null in the database and perhaps an empty string to represent null in the database and have code in the update to look for these special values and then set the entity property to null. Far from ideal and likely to be prone to bugs.
Here is the code I currently have to process the update. I would really really appreciate advice as to a better, perhaps more obvious way of doing this.
To Summerise: How can I tell which properties on an model instance have been set by the DataContractSerializer/DataContractJsonSerializer and which are just using default values from it's constructor. Using special values is problematic as the client might want to set something to an empty string, or to 0 or -1 or indeed to null.
public T Update(T obj)
{
var entity = ds.Attach(obj);
// For each property in the model
foreach (var p in typeof(T).GetProperties())
{
// Get the value of the property
var v = p.GetValue(obj, null);
// Assume null means that the property wasn't passed from the client
if (v == null)
continue;
// Set this property on the entity to modified unless it's ID which won't change
if (p.Name != "ID")
dc.Entry(entity).Property(p.Name).IsModified = true;
}
dc.SaveChanges();
return entity;
}
UPDATE: Using Hammerstein's answer below to have self tracked models, I've updated my update function as below. Unfortunately due to my use of the Required attribute on the models for pre-save validation EF throws a wobbly when using a stub instance that contains nulls for the non modified values. You would think that EF would realise as part of it's validation that some fields are set to not modified but alas it doesn't so I'm forced to do a read and then update that. Actually this might be a good candidate for a separate question to post to try and avoid the read.
public virtual T Update(T obj)
{
var entity = ds.Find(obj.ID);
((TrackedModel)obj).Modified.ForEach(p => {
var prop = dc.Entry(entity).Property(p.PropertyName);
prop.CurrentValue = p.NewValue;
prop.IsModified = true;
});
dc.SaveChanges();
return entity;
}
My solution to this problem was a tracked change model, I created an abstract base class that had a list of strings, then for each property on my model, I called a method NotifyChanged( "MyProperty") which added the property to the list.
Because model binding will only set the fields that have been posted back, you should get an accurate list of fields that changed.
Then I loop through the list, and set the values on my entity.
Not clean, but it worked for my purpose.
Update: My solution did require me to get away from auto-properties and to hand write them. In the setter, after setting the value, I call NotifyChanged. I'm using this with MVC regular model binding, I don't think I have a working example of passing an object as JSON and deserializing. You could look at JSON.NET, controlling the serialization/deserialization I believe you can tell it to ignore default property values etc.