Ok, I am attempting to use this custom extension to perform an entity update. Right now it should update all properties and then all of its related ends (references). The problem is even though the entity with changes does have a related end with an entity key that is valid and correct (verified in the debugger its there). When the RelationshipManager gets it they key is null.. Anyone see anything wrong with this code?
public static void ApplyChanges(this ObjectContext context, EntityObject entityWithChanges)
{
if (entityWithChanges.EntityState == EntityState.Detached)
{
object entityCurrentlyInDB = null;
if (context.TryGetObjectByKey(entityWithChanges.EntityKey, out entityCurrentlyInDB))
{
context.ApplyPropertyChanges(entityWithChanges.EntityKey.EntitySetName, entityWithChanges);
foreach (var relatedEnd in ((IEntityWithRelationships)entityCurrentlyInDB).RelationshipManager.GetAllRelatedEnds())
{
var oldRef = relatedEnd as EntityReference;
if (oldRef != null)
{
var newRef =
((IEntityWithRelationships)entityWithChanges).RelationshipManager
.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference;
oldRef.EntityKey = newRef.EntityKey;
}
}
}
else
{
throw new ObjectNotFoundException();
}
}
}
This is just a modified version of what I found
Here
Appreciate the help.
UPDATE:
This is the Update Method
public static void UpdateTemplate(Template template)
{
using (TheEntities context = new TheEntities())
{
context.ApplyChanges(template);
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException)
{
context.Refresh(RefreshMode.ClientWins, template);
context.SaveChanges();
}
context.RemoveTracking(template);
}
}
This is the unit test:
[TestMethod]
public void CanUpdateATemplate()
{
Template template = new Template();
template.Name = "Test";
template.Description = "Test";
TemplateType type = TemplateManager.FindTemplateTypeByName("Test");
if (type == null)
{
type = new TemplateType();
type.Name = "Test";
}
template.TemplateType = type;
TemplateManager.AddTemplate(template);
template = TemplateManager.FindTemplateByID(template.TemplateID);
Assert.IsNotNull(template);
type = TemplateManager.FindTemplateTypeByName("Round");
if (type == null)
{
type = new TemplateType();
type.Name = "Round";
}
template.TemplateType = type;
TemplateManager.UpdateTemplate(template);
template = TemplateManager.FindTemplateByID(template.TemplateID);
Assert.IsNotNull(template);
Assert.IsTrue(template.TemplateType.Name == "Round");
TemplateManager.DeleteTemplate(template);
template = TemplateManager.FindTemplateByID(template.TemplateID);
Assert.IsNull(template);
}
This is simply not possible due to the way Detach works in EF.
I found that if I added key information myself I could get the generic call to work and even save it.
The problem is that the moment you go to return an entity after calling Detach on it you lose all relationship data. Ive found some write ups on writing graph managers for each entity but I find that a waste seeing as EF should do this stuff (supposedly it will in v2).
EF simply is not ready for N-Tier deployments.
Related
i tried this method that I created but it prompts me an error:
Realms.RealmInvalidObjectException:This object is detached. Was it deleted from the realm?'
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
using (var transaction = Realm.GetInstance(config).BeginWrite())
{
Realm.GetInstance(config).Remove(denom_list[0]);
transaction.Commit();
}
}
what is the proper coding for deleting records from database in realm in C# type of coding?
You are doing it the right way. The error message you are getting indicates that the object was removed already. Are you sure it still exists in the realm?
UPDATE:
I decided to update this answer because my comment on the other answer was a bit hard to read.
Your original code should work fine. However, if you want deleteFromDatabase to accept lists with CashDenomination instances that either have been removed already or perhaps were never added to the realm, you would need to add a check. Furthermore, note that you should hold on to your Realm instance and use it in the transaction you created. In most cases, you want to keep it around even longer, though there is little overhead to obtaining it via GetInstance.
public void deleteFromDatabase(List<CashDenomination> denom_list)
{
if (!denom_list[0].IsValid) // If this object is not in the realm, do nothing.
return;
var realm = Realm.GetInstance(config);
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom_list[0]);
transaction.Commit();
}
}
Now, if you want to use identifiers, you could look it up like you do, but still just use Remove:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.All<CashDenomination>().FirstOrDefault(c => c.denom_id == denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
Finally, if your CashDenomination has denom_id marked as PrimaryKey, you could look it up like this:
public void deleteFromDatabase(int denom_id)
{
var realm = Realm.GetInstance(config);
var denom = realm.ObjectForPrimaryKey<CashDenomination>(denom_id);
if (denom == null) // If no entry with this id exists, do nothing.
return;
using (var transaction = realm.BeginWrite())
{
realm.Remove(denom);
transaction.Commit();
}
}
public void deleteFromDatabase(Realm realm, long cashDenominatorId)
{
realm.Write(() =>
{
var cashDenominator = realm.All<Person>().Where(c => c.Id == cashDenominatorId);
Realm.RemoveRange<CashDenomination>(((RealmResults<CashDenomination>)cashDenominator));
});
}
Which you would call as
Realm realm = Realm.GetInstance(config);
var denom_list = ...
// ...
deleteFromDatabase(realm, denom_list[0].id);
I already made it having this code :) thanks to #EpicPandaForce 's answer.
public void deleteFromDatabase(int denom_ID, int form_ID)
{
//Realm realm;
//and
//RealmConfiguration config = new RealmConfiguration(dbPath, true);
//was initialized at the top of my class
realm = Realm.GetInstance(config);
realm.Write(() =>
{
var cashflow_denom = realm.All<CashDenomination>().Where(c => c.denom_id == denom_ID);
var cashflow_form = realm.All<CashForm>().Where(c => c.form_id == form_ID);
realm.RemoveRange(((RealmResults<CashDenomination>)cashflow_denom));
realm.RemoveRange(((RealmResults<CashForm>)cashflow_form));
});
}
it is now deleting my data without exception :)
When I try to update this object in EF6 I get an error stating more than 1 entity has this primary key. Looking at this DB I know this to be untrue(from what I can see).
I need to be able to update a second object based on one of the properties on the posted object. The code below produces the error. I have left in commented out pieces that I have tried to get this to work.
public async Task<ActionResult> Edit(PricingRule pricingRule)
{
if(ModelState.IsValid)
{
var currentUser = await serv.UserManager.FindByIdAsync(User.Identity.GetUserId());
var company = currentUser.Company;
//var entityRule = serv.PricingService.PricingRules.Get(pricingRule.PricingRuleId);
//If this is the first rule, set it to the company default
var rulesCount = company.PricingRules.Count;
if (rulesCount <= 1 || company.DefaultPricingRule == null)
pricingRule.DefaultPricingRule = true;
//Make sure no other rules are marked as default, and update the company with this rule as default
if (pricingRule.DefaultPricingRule)
{
if (company.DefaultPricingRule != null)
{
var oldRule = serv.PricingService.PricingRules.Get(company.DefaultPricingRule.PricingRuleId);
oldRule.DefaultPricingRule = false;
//serv.PricingService.PricingRules.Update(oldRule);
}
company.DefaultPricingRule = pricingRule;
serv.CoreService.Companies.Update(company);
}
serv.PricingService.PricingRules.Update(pricingRule);
await serv.SaveAllChangesAsync();
return RedirectToAction("Index");
}
return View(pricingRule);
}
Whether or not it is the best practice or how it should technically be done, this is how I solved my problem.
The edited object I was passing in, needed to be marked as modified first, before doing any other operations. I am assuming this is because the context could then grab it and all other operations regarding it would be done "within context". Other wise I think it was trying to add a new object if I tried to attach it to company.DefaultPricingRule.
public async Task<ActionResult> Edit(PricingRule pricingRule)
{
if(ModelState.IsValid)
{
serv.PricingService.PricingRules.Update(pricingRule);
var currentUser = await serv.UserManager.FindByIdAsync(User.Identity.GetUserId());
var company = currentUser.Company;
//If this is the first rule, set it to the company default
var rulesCount = company.PricingRules.Count;
if (rulesCount <= 1 || company.DefaultPricingRule == null)
pricingRule.DefaultPricingRule = true;
//Make sure no other rules are marked as default, and update the company with this rule as default
if (pricingRule.DefaultPricingRule)
{
if (company.DefaultPricingRule != null)
{
var oldRule = serv.PricingService.PricingRules.Get(company.DefaultPricingRule.PricingRuleId);
oldRule.DefaultPricingRule = false;
serv.PricingService.PricingRules.Update(oldRule);
}
company.DefaultPricingRule = pricingRule;
serv.CoreService.Companies.Update(company);
}
await serv.SaveAllChangesAsync();
return RedirectToAction("Index");
}
return View(pricingRule);
}
If Anyone has a comment on if this is best practice or if there is a better way to do it, I gladly take criticism.
I see two codes for adding and deleting entity, I wonder which is the best way and what is the difference between these two.
One is this (for Adding):
using (var context = new BloggingContext())
{
var blog = new Blog { Name = "ADO.NET Blog" };
context.Blogs.Add(blog);
context.SaveChanges();
}
and another is this:
using (var context = new BloggingContext())
{
var blog = new Blog { Name = "ADO.NET Blog" };
context.Entry(blog).State = EntityState.Added;
context.SaveChanges();
}
and I read that calling the Add method on DbSet puts the entity into the Added state.
According to this I think above two codes are nearly same. If its not please tell me the difference.
And another code I've found is:
public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Added)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}
and if its true that calling the Add method on DbSet puts the entity into the Added state then I think there is no difference in code in if and else block, so what's the point in here.
And from the above three code which is the best way to add an Entity.
And another code in which I have doubt is what is the use of else block in below code:
public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}
I don't see a huge benefit in setting the state of an entity to Added since creating a new entity and adding it to the set does exactly that like you mentioned. Where this type of pattern is pretty useful is when you want to delete an entity without having to fetch it from the database first:
// this entity will be unattached at this point, so if you were to call remove
// on the dbset it wouldn't do much, since it doesn't think it's in the database
var deleteThisEntity = new Blog { Id = 5 };
// if you set the state to deleted, it now thinks that it needs to be deleted
db.Entry(deleteThisEntity).State = EntityState.Deleted;
// call SaveChanges to delete
db.SaveChanges();
You can get a similar effect by setting the state to modified, so it will trigger an update statement. Sometimes you just don't want to take the extra hit of fetching an item from the database just to delete it.
ADD Patterns for ASP .NET using the code bellow is very standard practice.
using (var context = new BloggingContext())
{
var blog = new Blog { Name = "ADO.NET Blog" };
context.Blogs.Add(blog);
context.SaveChanges();
}
In the code for delete, the if/else statement is to check if the fetched object is valid.
The code I've been using for DELETE patterns is this:
var fetchedObject = context.Blog.Find(id);
if (fetchedObject == null)
{
return false;
}
else
{
ds.Blog.Remove(fetchedObject);
return true;
}
This is a method inside a Manager class that receives the id.
Ok here is the deal. using my Model to raise the Child_Update() Method. I know it is not good but im just learing right now. Now i given my Business class as Parameter to Change the already given rows.
It's doin everything fine without any error Messages and there is also no null variable but it's not changing anything in the database.
here i'm using the selectedIndex to choose the right items to update
public void ExecuteAngestellte(object obj)
{
try
{
_selectedIndex.Child_Update(new Farbe { FarbauswahlNr = SelectedIndex.FarbauswahlNr, Kurztext = SelectedIndex.Kurztext, Ressource = SelectedIndex.Ressource, Vari1 = SelectedIndex.Vari1, Vari2 = SelectedIndex.Vari2 });
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
and here's the child update
public void Child_Update(Farbe data)
{
using (var ctx =Csla.Data.ObjectContextManager<TestDBEntities>.GetManager(EntitiesDatabase.Name))
{
var objectStateManager = ctx.ObjectContext.ObjectStateManager;
var _data = new Datenbank.Farbe();
_data.FarbauswahlNr = data.FarbauswahlNr;
_data.Kurztext = data.Kurztext;
_data.Ressource = data.Ressource;
_data.Var1 = data.Vari1;
_data.Vari2 = data.Vari2;
ctx.ObjectContext.SaveChanges();
}
}
thx for help
as far as I can tell, your _data is not part of the datacontext
I am not sure what the variables all mean so here is a simple update I use for a single record with entity framework
public void UpdateTable(int idRecord, YourContext Context)
{
MyRecord = Context.MyTable.Find(idRecord);
myRecord.Column = "New Value";
Context.SaveChanges();
}
so I think you need to do:
var MyData = ctx.ObjectContext.TableName.Find(id)
I am assuming you are using entity framework. Does this help?
I am attempting to simply check a list of Managed Properties for a specific property. In theory, not difficult. In practice, it is proving to give me trouble. The first approach I found is as follows:
static void Main(string[] args)
{
try
{
string strURL = "http://<SiteName>";
Schema sspSchema = new Schema(SearchContext.GetContext(new SPSite(strURL)));
ManagedPropertyCollection properties = sspSchema.AllManagedProperties;
foreach (ManagedProperty property in properties)
{
if (property.Name.Equals("ContentType")
{
Console.WriteLine(property.Name);
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
This pulled back exactly what I wanted. However, the issue with this is that Visual Studio 2012 says that SearchContext is obsolete and depricated, and that I should use SearchServiceApplication instead. So I did some more searching and found the following:
SPServiceContext context = SPServiceContext.GetContext(SPServiceApplicationProxyGroup.Default, SPSiteSubscriptionIdentifier.Default);// Get the search service application proxy
var searchProxy = context.GetDefaultProxy(typeof(SearchServiceApplicationProxy)) as SearchServiceApplicationProxy;
if (searchProxy != null)
{
SearchServiceApplicationInfo ssai = searchProxy.GetSearchServiceApplicationInfo();
var application = SearchService.Service.SearchApplications.GetValue<SearchServiceApplication>(ssai.SearchServiceApplicationId);
var schema = new Schema(application);
ManagedPropertyCollection properties = schema.AllManagedProperties;
foreach (ManagedProperty property in properties)
{
if (property.Name.Equals("ContentType")
{
Console.WriteLine(property.Name);
}
}
}
The problem I run into with this is an EndpointNotFoundException.
I'm guessing I am just configuring the second option incorrectly as the first method can find everything just fine. Can anyone shed some light on anything obviously wrong that I am missing?
Any tips/hints will be appreciated!
This chunk of code should get you what you want.
foreach (SPService service in SPFarm.Local.Services)
{
if (service is SearchService)
{
SearchService searchService = (SearchService)service;
foreach (SearchServiceApplication ssa in searchService.SearchApplications)
{
Schema schema = new Schema(ssa);
foreach (ManagedProperty property in schema.AllManagedProperties)
{
if (property.Name == "ContentType")
{
//Handle here
}
}
}
}
}