Comparing old (cached) entity with updated entity without angering nhibernate - c#

I am updating an entity in a form, for simplicity, lets call it CompanyCar. My objective is to check and see if its assigned owner has changed, and if so, send an email to the old and new owner.
public Car SaveExistingCar(Car car)
{
var original = _CarRepository.LoadCarById(Car.Id);
var carReturn = _CarRepository.SaveOrUpdateCar(Car) //Error here
//pseudo: if carReturn.Owner != original.Owner
// Send Email
return carReturn;
}
Unfortunately it gets mighty angry about this.
a different object with the same identifier value was already associated with the session
I can understand whats making that happen... sure, okay its confused about the real object. However, that doesn't do much to help me solve it. Is there something I can do to tell it that the 'original' is bogus?

ISession.Evict will remove the original car from the session and 1st level cache and you should be able to save the new car.

Related

C# Google SDK Update or Patch User

Having problem using update User with the google Admin SDK for C#.
https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/update
This method supports patch semantics, meaning you only need to include the fields you wish to update. Fields that are not present in the request will be preserved, and fields set to null will be cleared.
This differs from the Patch as patch won't clear fields that are null but only update fields that have a value.
Problem is that I have to pass a full Google.Apis.Admin.Directory.directory_v1.Data.User class to the function which will contain null of even properties i do not want to clear.
example:
public User UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
{
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(gUser, gUser.Id);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Is there any way of modifying the Body in UpdateRequest before executing it?
Edit:
The UpdateRequest has a ModifyRequest Property that looks like this
I just have no Idea how to use it, any ideas?
public Action<HttpRequestMessage> ModifyRequest { get; set; }
As far as updating things to the concept of Null that is not something that can be done with PATCH. I recommend setting it to an empty string.
You should also not be sending the full user object if thats what you are currently doing. I am going to assume that you have done a users.list to find the user you want to update and change something in that user, say the name. Then you have simply submited the full user object to your method
UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
This wont work as some of the fields you have sent as part of the update/patch are not actually writeable.
What you should do instead would be to create a new user object change what ever it is you want
public User MakeUserAdmin(Google.Apis.Admin.Directory.directory_v1.Data.User gUserId)
{
var updateFields= new Google.Apis.Admin.Directory.directory_v1.Data.User();
change.IsAdmin = true;
change.Addresses = ""; // will set it to empty yes not null but the best you can do with this api.
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(updateFields, gUserId);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Notice how you just need to create a new object and update only the fields you need then send that.
Dont try to update every field, just update the ones that you know have changed. Dont include the id in the object that is not writeable either.

How to check this exact class isn't already in DB with another name? (MongoDB)

Using C# and MongoDb im saving a class similar to the following.
public class Zone
{
public string ZoneName { get; set; }
public List<string> IncludedCountries { get; set; } = new List<string>();
}
This is filled by user and saved in my DB, currently I am checking that the zone name isn't duplicated when inserting. Like so.
if (All().Any(x => x.Name.ToLower() == zone.Name.ToLower())) { throw new System.Exception($"Zone \"{zone.ZoneName}\" is already in database, please edit the zone"); };
But if user currently tries to add the exact same values (So exact same list of included countries) with different name, I wouldn't catch it.
I want to be able to, as dont want to be duplicating same classes in DB (My actual class will have more properties, this is an example). I am aware I can check it the same way im checking for name, but having in mind I have a lot of properties, i'd like to know what the best way is..
Ideally you wouldn't perform a search, then use that to decide whether to add or not. In a collaborative system with potentially multiple users you could find another user in another transaction runs the same code at the same time, and ends up adding the record just after your check, but just before your insert.
It's better, assuming your datastore supports it, to use a uniqueness constraint on some value of the data you're inserting. Here's the docs for Mongo: https://docs.mongodb.com/manual/core/index-unique/
This means the transaction will be failed by the database if you attempt to insert a duplicate. To be fair, there's nothing wrong with doing the "ask-then-tell" as well I suppose, in order to avoid ugly exceptions being shown to users, but if you're able to interrogate the exception details you can probably catch it and show the user some helpful information rather than letting them see an error page.
To support your requirement for "has the same list of things" in this way, I'd suggest creating a SHA256 hash value (here's a link: https://stackoverflow.com/a/6839784/26414) for the list, and storing that as a property in it's own right. Just make sure it's recalculated if the list changes.
One additional thing - technically "class" defines the schema, or shape of a bit of data. When you create an instance of a class at runtime, which has actual values and takes up memory, that's technically an "object". So an "object" is an "instance" of a "class".

Creating Discount Coupons in Kentico 7

So I'm trying to create discount coupons for a Kentico 7 site, and I'm not sure if I'm completely misunderstanding how the DiscountCouponInfoProvider works, or if I'm barking up the wrong tree entirely.
The code I'm currently using is:
var newCoupon = new DiscountCouponInfo {
//Fill in data fields here
};
DiscountCouponInfoProvider.SetDiscountCouponInfo(newCoupon);
This doesn't throw an error, but the coupon never shows up in the database. A few lines down I use
var result = DiscountCouponInfoProvider.GetDiscountCouponinfo();
passing in the same ID I used when creating the coupon, and it stores all of the correct information in result.
I noticed that there is an insert method for the DiscountCouponInfo class
newCoupon.Insert();
which may be closer to what I'm looking for, but haven't tried yet.
Any help would be appreciated. Or a link to the Kentico 7 api reference. Every time I go looking for it I keep finding the Kentico 8.1 api reference.
Thanks.
You can create coupons within the Kentico UI by going to CMS Desk > Ecommerce > Discount Coupons. However, if you are needing to create them outside the UI for some reason, then you were pretty close. You will want to use an Info object along with the InfoProvider object, like this:
// Instantiate an info object
DiscountCouponInfo dci = new DiscountCouponInfo();
// Set your properties
dci.DiscountCouponDisplayName = "Some text";
dci.DiscountCouponValue = 10;
//Update the DB with an InfoProvider object
DiscountCouponInfoProvider.SetDiscountCouponInfo(dci);
The Info object is just a simple data container that you can instantiate, populate with data, then pass it as an argument to an InfoProvider object.
The InfoProvider then has methods for update/creating records, etc.
You could also populate an Info object with data from the Kentico DB like this:
DiscountCouponInfo dci = new DiscountCouponInfoProvider.GetDiscountCouponInfo(DiscountCouponID);
I actually JUST wrote a blog post about this. Feel free to check it out or read Kentico's docs for more info.

Obtaining the value of an option in a picklist

I'm creating a phony instance of an entity beep. It has a required field of type picklist called pickaboo. First I omitted it but then the application started to lament throwing error messages at me due to some business logic demanding all the newly created instances of beep to have that field assigned.
Entity entity = new Entity { LogicalName = "beep" };
Guid guid = proxy.Create(entity);
proxy.Delete("beep", guid);
I don't give a rodent's tail section about that demand because right after I've created the instance, I'm removing it. However CRM gives a huge rodent and doesn't let me do my magic. So, I went clever and added an attribute for the missing attribute.
OptionSetValue option = new OptionSetValue(0);
Entity entity = new Entity { LogicalName = "beep" };
entity.Attributes.Add("pickaboo", option);
Guid guid = proxy.Create(entity);
proxy.Delete("beep", guid);
Of course, it didn't work because zero isn't a valid value. Apparently, CRM adds a hash number based on the solution so the actual "zero" has the numeric value like "846000000000", the actual "one" has "846000000001" etc.
How can I obtain that value programmatically?
Right now I have an ugly workaround obtaining all the beeps and getting the value from the first of them. Don't even get me started on how much sleep I'm loosing knowing how embarrassing it looks, would anybody take time to give me some feed-back. :(
You've got two options.
You can use the CrmSrvcUtil to generate your OptionSetValues as enums... This would create a pickaboo enum that you could then reference in your code
entity.Attributes.Add("pickaboo", new OptionSetValue((int)pickaboo.YourEnumValue);
You could also use the RetrieveOptionSetRequest message to get a list of all values for the particular option set you're interested in. See this SO question
Since I know that all CRM programmers are lazy pigs (own experience, haha), I know that you'd prefer a short and comprehensive solution. I realize that you're looking for a quick access to just a single valid value. If I'm mistaken, stop reading - use the suggestion of #Daryl - he's got a good answer for ya.
If I'm right, though, use this code to get the first valid option value (provided it exists). Just in case, remember to surround it with try/catch so if you misspell or such, you won't end up scratching your head.
RetrieveAttributeRequest request = new RetrieveAttributeRequest
{
EntityLogicalName = "beep",
LogicalName = "pickaboo",
RetrieveAsIfPublished = true
};
RetrieveAttributeResponse response
= proxy.Execute(request) as RetrieveAttributeResponse;
PicklistAttributeMetadata metaData
= response.AttributeMetadata as PicklistAttributeMetadata;
OptionSetValue option
= new OptionSetValue(metaData.OptionSet.Options[0].Value ?? -1);
NB - I'm assuming that you've got a working connection via a proxy called proxy.
Set a try/catch around the whole code, just in case out of bound exception occurs.
Make sure to handle the option of -1, since Value returned is a nullable integer.
This question has inspired me to blog.
If you have a look at my post below its got a function that can be used to find the int values of picklists (global and local optionsets), statecode, statuscode and the boolean (two option) fields.
CRM 2011 Programatically Finding the Values of Picklists, Optionsets, Statecode, Statuscode and Boolean (Two Options)

Retrieve an object in one DB4O session, store in another ('disconnected scenario')

I am trying to figure out how to keep an object useable between client sessions in DB4O. From what I understand, once a client session is closed, the object no longer resides in any cache and despite the fact that I have a valid UUID, I cannot call Store on it without causing a duplicate to be inserted. I searched for a way to manually re-add it to the cache but there is no such mechanism. Re-retrieving it will force me to copy over all the values from the now useless object.
Here's the above paragraph in code:
Person person = new Person() { FirstName = "Howdoyu", LastName = "Du" };
Db4oUUID uuid;
// Store the new person in one session
using (IObjectContainer client = server.OpenClient())
{
client.Store(person);
uuid = client.Ext().GetObjectInfo(person).GetUUID();
}
// Guy changed his name, it happens
person.FirstName = "Charlie";
using (var client = server.OpenClient())
{
// TODO: MISSING SOME WAY TO RE-USE UUID HERE
client.Store(person); // will create a new person, named charlie, instead of changing Mr. Du's first name
}
The latest version of Eloquera supports these scenarios, either through an [ID] attribute or via Store(uid, object).
Any thoughts?
This functionality is indeed missing in db4o =(. That makes db4o very difficult to use in many scenarios.
You basically have to write your own reattach method by coping all attributes over. Maybe a library like Automapper can help, but in the end you have to do it yourself.
Another question is if you really want to use the db4o UUIDs to identify an object. db4o UUIDs are huge and not a well known type. I personally would prefer regular .NET GUIDs.
By the way: There's the db4o .Bind() method, which binds a object to an existing id. However it hardly does what you really want. I guess that you want to store changes made to an object. Bind basically replaces the object and breaks the object graph. For example if you have a partially loaded objects and then bind it, you loose references to objects. So .Bind is not usable.
Okay, Gamlor's response about the db4o IExtContainer.Bind() method pointed me to the solution. Please note that this solution is only valid in very specific situations where access to the DB is tightly controlled, and no external queries can retrieve object instances.
Warning: This solution is dangerous. It can fill your database with all kinds of duplicates and junk objects, because it replaces the object and doesn't update its values, therefore breaking any references to it. Click here for a complete explanation.
UPDATE: Even in tightly controlled scenarios, this can cause endless headaches (like the one I'm having now) for anything other than a flat object with value type properties only (string, int, etc.). Unless you can design your code to retrieve, edit and save objects in a single db4o connection, then I recommend not to use db4o at all.
Person person = new Person() { FirstName = "Charles", LastName = "The Second" };
Db4oUUID uuid;
using (IObjectContainer client = server.OpenClient())
{
// Store the new object for the first time
client.Store(person);
// Keep the UUID for later use
uuid = client.Ext().GetObjectInfo(person).GetUUID();
}
// Guy changed his name, it happens
person.FirstName = "Lil' Charlie";
using (var client = server.OpenClient())
{
// Get a reference only (not data) to the stored object (server round trip, but lightweight)
Person inactiveReference = (Person) client.Ext().GetByUUID(uuid);
// Get the temp ID for this object within this client session
long tempID = client.Ext().GetID(inactiveReference);
// Replace the object the temp ID points to
client.Ext().Bind(person, tempID);
// Replace the stored object
client.Store(person);
}

Categories

Resources