I have this code inside my HTTP PUT Method;
var toUpdate = context.MyTableData.SingleOrDefault(a => a.id == someId);
id = data.id,
name = data.name,
age = data.age,
JObject otherData = (JObject)data;
JToken value;
if(otherData.TryGetValue("children", out value)){
var someIds = (JArray)value;
foreach (var someId in someIds){
toUpdate.MyChildrenTable.Add(new MyChildrenTable{ //-- This line right here
id = data.id,
name = data.name,
age = data.age,
}
}
}
Based on the code, I only wanted to update to update my data. However, using Add, this gives me another set of data (which is, obviously not updating the data). How I may able to modify my code? I tried using Attach but no good. Is there any way like Attach or something to have my code corrected?
To avoid confusions, all of the code are working. I only wanted to modify it in order to have it's flow Update my data instead of Adding another set of data. MyTableData is updating, but the MyChildrenTable is not, since it's on Add method.
Related
I have Ilist to get all Offer from repository using entity framework core. Also I have service model OfferResponseModel which includes
OfferRequestModel as reference. I used mapster to bind entity model to service model. However it only set first child. Now I want to bind it manually. I created "offers" with the size of "Offer". When I try to use foreach loop, I cannot set "offers" child element.Because it has no elements. So, I can I solve this.
var offer = await _unitOfWork.Offers.GetAllOffer();
if (offer == null)
throw ServiceExceptions.OfferNotFound;
var results = new List<OfferResponseModel>(offer.Count);
results.ForEach(c => { c.Offer = new OfferRequestModel(); });
int i = 0;
foreach(var result in results)
{
result.Offer.User = Offer[i].User.Adapt<UserResponseModel>();
result.Offer.Responsible = Offer[i].Responsible.Adapt<EmployeeResponseModel>();
result.CreatedDate = Offer[i].CreatedDate;
result.ModifiedBy = Guid.Parse(Offer[i].UpdatedBy);
result.Active = Offer[i].Status;
result.Offer = Offer[i].Offer;
result.Offer.User.Company = Offer[i].Company.Adapt<CompanyModel>();
i++;
}
I created "offers" with the size of "Offer".
No, you created it with that capacity. It's still an empty list. It's not clear to me why you're trying to take this approach at all - it looks like you want one OfferResponseModel for each entry in offer, directly from that - which you can do with a single LINQ query. (I'm assuming that offer and Offer are equivalent here.)
var results = Offer.Select(o => new OfferResponseModel
{
Offer = new OfferRequestModel
{
User = o.User.Adapt<UserResponseModel>(),
Responsible = o.Responsible.Adapt<EmployeeResponseModel>()
},
CreatedDate = o.CreatedDate,
ModifiedBy = Guid.Parse(o.UpdatedBy),
Active = o.Status
}).ToList();
That doesn't set the Offer.User.Company in each entry, but your original code is odd as it sets the User and Responsible properties in the original Offer property, and then replaces the Offer with Offer[i].Offer. (Aside from anything else, I'd suggest trying to use the term "offer" less frequently - just changing the plural to "offers" would help.)
I suspect that with the approach I've outlined above, you'll be able to work out what you want and express it more clearly anyway. You definitely don't need to take the "multiple loops" approach of your original code.
One thing you have left out is the type of the offer variable that is referenced in the code. But I am thinking you need to do something along these lines:
if (offer == null)
throw ServiceExceptions.OfferNotFound;
var results = offer.Select(o => new OfferResponseModel
{
Offer = new OfferRequestModel
{
User = o.User.Adapt<UserResponseModel>(),
Responsible = o.Responsible.Adapt<EmployeeResponseModel>(),
...
}
}).ToList();
Select basically loops through any items in offer and "converts" them to other objects, in this case OfferResponseModel. So inside select you simply new up an OfferResponseModel and directly sets all the properties you need to set.
You need using System.Linq; for Select to be available.
I'm trying to retrieve only the attributes for a certain entity, that have changed metadata since the last metadataquery - for example: if a user changes the requirement on a certain field of a certain entity, and saves and publishes this change, I want a plugin that fires on message Publish & PublishAll to let me know what attribute and which metadata of that attribute has changed.
This is the code I have so far, based on this example on MSDN: https://msdn.microsoft.com/en-us/library/jj863605.aspx?f=255&MSPPError=-2147217396
I get the attributes for the three entities that are listed in includedEntities, so no problem there.
I get values for RequiredLevel and IsValidForAdvancedSearch, the two attribute properties listed in attributeProperties and the ones I want to watch while the rest returns null, so again, no problem here.
The attributeFilter also does what it's supposed to do: I only get datafields (attributes that do not describe another attribute), so once again: no problem.
The clientversionstamp I pass on is retrieved from a configurationparameter I created, which I update after every query. By watching it during debug, I know that it's the correct value - so I'm quite sure that's not the problem either.
So what is the problem? For each entity, I still have some (about half) of the attributes that are added to the collection of changed attributes in the response, although I didn't change anything.
If I do change something in metadata, that attribute does get added to the response collection as well, so my code does pick up the change. However, I still get a lot more data than I want - the goal is to only get that one attribute that has changed. What am I missing?
MetadataFilterExpression EntityFilter = new MetadataFilterExpression(LogicalOperator.And);
EntityFilter.Conditions.Add(new MetadataConditionExpression("LogicalName", MetadataConditionOperator.In, includedEntities));
MetadataPropertiesExpression EntityProperties = new MetadataPropertiesExpression()
{
AllProperties = false
};
EntityProperties.PropertyNames.AddRange(new string[] { "Attributes" });
MetadataConditionExpression optionsetAttributeName = new MetadataConditionExpression("AttributeOf", MetadataConditionOperator.Equals, null);
MetadataFilterExpression AttributeFilter = new MetadataFilterExpression(LogicalOperator.And);
AttributeFilter.Conditions.Add(optionsetAttributeName);
MetadataPropertiesExpression AttributeProperties = new MetadataPropertiesExpression() { AllProperties = false };
foreach (string attrProperty in attributeProperties)
{
AttributeProperties.PropertyNames.Add(attrProperty);
}
EntityQueryExpression entityQueryExpression = new EntityQueryExpression()
{
Criteria = EntityFilter,
Properties = EntityProperties,
AttributeQuery = new AttributeQueryExpression()
{
Properties = AttributeProperties,
Criteria = AttributeFilter
}
};
RetrieveMetadataChangesRequest req = new RetrieveMetadataChangesRequest()
{
Query = entityQueryExpression,
ClientVersionStamp = clientVersionStamp
};
return (RetrieveMetadataChangesResponse)service.Execute(req);
I have the following code:
model = new Option();
model.val1 = newVal1;
model.val2 = newVal2;
model.val3 = newVal3;
//this saves new record just fine
if (recordCount < 1)
{
context.Options.AddObject(model);
context.SaveChanges();
}
else
{
var tempID = from s in context.Options where (s.val1 == newVal1 && s.val2 == newVal2) select s.ID;
var resultsID = tempID.First();
model = context.Options.Single(m => m.ID == resultsID);
if (TryUpdateModel(model, new[] { "val3" }))
{
//this isn't updating the record
context.SaveChanges();
}
}
The database adds a new entry just fine, but isn't updating it. What am I missing? Thanks.
Looking at this code, you first make a new model and set some properties on it:
model = new Option(); // <- A
model.val1 = newVal1;
model.val2 = newVal2;
model.val3 = newVal3;
then, assuming you're heading down the "else" path you do this:
var tempID = from s in context.Options where (s.val1 == newVal1 && s.val2 == newVal2) select s.ID;
var resultsID = tempID.First();
model = context.Options.Single(m => m.ID == resultsID); // <- B
if (TryUpdateModel(model, new[] { "val3" }))
{
//this isn't updating the record
context.SaveChanges();
}
which goes out and finds the entry in context.Options that has the matching ID.
So, now that model, which you created via the new() call (which I've marked with the comment "A") is now cast adrift and you've got a different one - the one you retrieved via the call to context.Options.Single(), which I've marked with the comment "B". It has properties based on what's in the context, not what was in that object you made. That A object is gone now. You've got a new object, B, retrieved from the DB.
So now, you're calling TryUpdateModel on this retrieved object, telling it that val3 is updated, but the value hasn't changed, right? It's whatever you pulled from the context.
So, it's not going to update anything because the model object isn't the one you think it is... the one you updated is waiting to be garbage collected. The one you retrieved hasn't been updated because it still has whatever value it's got for the property val3.
Assuming I follow what you're trying to do here, that's why you're not seeing any updated values in the context.
If you want to change the value of the val3 property on that model object you've retrieved, you need to set it after you retrieve it, otherwise it is overwritten.
If you are using a global context, you will have to update the context itself because it is not soft-link to the database.
context.SaveChanges();
DbContext context = new DbContext();
Check if Configuration.AutoDetectChangesEnabled = true;
I'm using Linq2SQL and I'm pretty new to it.
I've got a User table and a UserData table, the idea being that properties for the User object can be added / removed by adding or removing rows in the UserData table. I did not come up with this particular design but I am more or less stuck with it (as long as I can come up with a solution)
alt text http://www.86th.org/linq2sqlproblem.jpg
I'd like to populate/bind "FirstName" on the User object by something along the lines of setting the value to:
UserData.Value WHERE UserData.ItemID == User.UserID AND KeyName = 'FirstName'
Similarly, LastName would be:
UserData.Value WHERE UserData.ItemID == User.UserID AND KeyName = 'LastName'
Description of the UserData Table:
UserData.ItemID is the FK (User.UserID)
UserData.KeyName is specifying the name of the property
UserData.Value is the actual value.
How would I setup my User object to handle this so I could do the normal CRUD functionality on this object and have the changes carry through to both tables?
Is this even possible?
Is this bad form?
Personally I feel its bad form but I suppose everyone has there way of doing things. Why can't you assign userdata in the users table? I think I might not be understanding the design idea here.
Quick Note
I renamed UserData to ExtendedProperty and this caused the relationship from User to ExtendedProperty to be called ExtendedProperties.
Summary of changes
Created a getter/setter for both FirstName and LastName in the partial User class
Grabbed the correct ExtendedProperty element out of the ExtendedProperties collection and either returned or updated the Value property of it.
Refactored into a reusable format as shown below
partial class User
{
public string FirstName
{
get { return (string)this.getExtendedProperty("FirstName").Value; }
set { this.getExtendedProperty("FirstName").Value = value; }
}
public string LastName
{
get { return (string)this.getExtendedProperty("LastName").Value; }
set { this.getExtendedProperty("LastName").Value = value; }
}
// Grab a related property out of the collection, any changes to it will be reflected in the database after a submit
private ExtendedProperty getExtendedProperty(string KeyName)
{
// grab the properties that fit the criterea
var properties = (from prop in this.ExtendedProperties where prop.KeyName == KeyName select prop);
// return value
ExtendedProperty property = properties.SingleOrDefault();
// if this is a new user then there arent going to be any properties that match
if (property == null)
{
// Define a new item to add to the collection
property = new ExtendedProperty()
{
ItemID = this.UserID,
KeyName = KeyName,
Value = String.Empty
};
// Add the item we're about to return to the collection
this.ExtendedProperties.Add(property);
}
// either way we have a valid property to return at this point
return property;
}
}
I just hope this isn't bloated / grossly inefficient.
Edit
In getExtendedProperty, it would error when setting the FirstName or LastName of a newly created User because it would not have any corresponding ExtendedProperty elements in the ExtendedProperties collection as shown below.
User expected = new User();
expected.UserID = Guid.NewGuid();
expected.UserName = "LJ";
expected.FirstName = "Leeroy"; // It would error here
expected.LastName = "Jenkins";
Because of this I added a check to ensure that new items get added to the ExtendedProperties collection if they are requested and not currently in there.
I also removed setExtendedProperty since I felt it wasn't necessary and was just a method around a 1 liner anyway.
I would really appreciate any feedback before I accept this answer, I'll let it sit for a few days.
Code below does not run correctly and throws InvalidOperationExcepiton.
public void Foo()
{
DataContext context = new DataContext();
LinqEntity item = new LinqEntity(){ Id = 1, Name = "John", Surname = "Doe"} ;
context.LinqEntities.Attach(item, true);
}
By default, the entities will use all fields for checking concurrency when making edits. That's what's throwing the InvalidOperationException.
This can be setting the Update Check property for all fields to Never. This must be done on all fields to attach the entity as modified. If this is done, an additional call to context.SubmitChanges() will save the data.
Alternatively, if you know the original values, you can attach and then make the updates, but all values that are being checked must match the original values.
LinqEntity item = new LinqEntity(){ Id = 1, Name = "OldName", Surname = "OldSurname"};
context.LinqEntities.Attach(item);
item.Name = "John";
item.Surname = "Doe";
context.SubmitChanges();
I'm not sure what you mean by disconnected from the database.
It appears that you are trying to insert a new row into the LinqEntities table -- is that correct?
If that is the case you'll want to do
context.LinqEntities.InsertOnSubmit(item);
context.Submit();
OK, if you're trying to update a row with ID = 1, you'll do it like this:
DataContext context = new DataContext();
LinqEntity item = (from le in context.LinqEntities
where le.ID == 1
select le).Single();
item.Name = "John";
item.Surname = "Doe";
context.Submit();
You could also replace the Linq expression with a more concise lambda:
LinqEntity item = context.LinqEntities.Single(le => le.ID == 1);
The most important thing the DataContext does is track any changes you make, so that when you call the Submit method it will autogenerate the Insert statements for the things you've changed.
When using an ORM you typically select an object before updating it.
You can use DataContext.ExecuteCommand(...) to bypass the ORM if you do not want to do a select.