I have the following method to save order properties on a purchase order:
public void SetOrderProperty(string orderPropertyName, string value)
{
PurchaseOrder purchaseOrder = TransactionLibrary.GetBasket().PurchaseOrder;
OrderProperty orderProperty = purchaseOrder.OrderProperties.FirstOrDefault(x => x.Key == orderPropertyName);
if (orderProperty != null)
{
orderProperty.Value = value;
orderProperty.Save();
}
else
{
OrderProperty op = new OrderProperty
{
Key = orderPropertyName,
Value = value,
Order = purchaseOrder
};
op.Save();
}
purchaseOrder.Save();
TransactionLibrary.ExecuteBasketPipeline();
}
When I save a value using this I can see it appear against the order in the uCommerce_OrderProperty table.
However, with some properties, when I try to read them back out they are missing:
public string GetOrderProperty(string orderPropertyName)
{
PurchaseOrder purchaseOrder;
using (new CacheDisabler())
{
purchaseOrder = TransactionLibrary.GetBasket().PurchaseOrder;
}
OrderProperty orderProperty = purchaseOrder.OrderProperties.FirstOrDefault(x => x.Key == orderPropertyName);
if (orderProperty != null)
{
return orderProperty.Value;
}
return string.Empty;
}
I have also tried this code from the uCommerce site:
public string GetOrderProperty(string orderPropertyName)
{
PurchaseOrder purchaseOrder = SiteContext.Current.OrderContext.GetBasket().PurchaseOrder;
return purchaseOrder[orderPropertyName];
}
If I inspect purchaseOrder I can see the OrderProperties are missing. I have 7 properties at any one time but purchaseOrder only ever seems to have a max of 5 even though there is 7 in the table.
These are Order Properties and not Order Line Properties. Can anyone give me any pointers as to why I am seeing this behaviour?
EDIT
This line does get the value I am looking for:
OrderProperty op = OrderProperty.FirstOrDefault(x => x.Order.OrderId == purchaseOrder.OrderId && x.Key == orderPropertyName);
Even when this line (called the line after) returns null:
OrderProperty orderProperty = purchaseOrder.OrderProperties.FirstOrDefault(x => x.Key == orderPropertyName);
(Both are looking for the same Order Property)
Can anyone tell me why?
I have a comment, but I'm not allowed because of missing reputation.
Everything seems to be fine regarding your code. Can I persuade you to show the
uCommerce_OrderProperty table?
- I just want to check that the OrderLineId column is empty for you order properties.
You should be able to set and get it like this:
var property = order[orderPropertyName];
order[orderPropertyName] = "VALUE";
Regards
Mads
We also recommend that Ucommerce related question is posted at http://eureka.ucommerce.net/, the response time is often faster.
Related
i am trying to get data from database passing a string value. but get null value instead of the data.
i have tried the following code
order getCustomerOrder(string or_n)
{
using (foodorderingEntities db = new foodorderingEntities ())
{
var result = db.orders.Where(or => or.order_no == or_n).FirstOrDefault();
return result;
}
}
please some one guide me to solve this problem.
Please paste your order object, so we know if its reference object/primitive etc, you can use this to understand the two ways to retrieve orders.
I would recommend you read this answer & this MSDN string compare, if your default culture is causing an issue in the comparison, it will help you understand whats going on
Options 1:
// Query syntax
IEnumerable<CustomerOrder> queryResultsCustomerOrder =
from order in orders
where order.number == myOrderNumber
select order;
Options 2:
// Method-based syntax
IEnumerable<CustomerOrder> queryResultsCustomerOrder2 = orders.Where(order => order.Number == myOrderNumber);
using the above, now you can get however many orders the customer has. I am assuming your order is a number, but you can change it to whatever like a string.
Int based order comparison sample
IEnumerable<CustomerOrder> getCustomerOrder(int myOrderNumber)
{
if(myOrderNumber <1) return null;
using (foodorderingEntities dbContextOrderSet = new foodorderingEntities())
{
IEnumerable<CustomerOrder> resultsOneOrManyOrders = orders.Where(order => order.Number == myOrderNumber);
return resultsOneOrManyOrders ;
}
}
string based order comparison
IEnumerable<CustomerOrder> getCustomerOrder(string myOrderNumber)
{
//no orders
if(String.IsNullOrEmpty(myOrderNumber)) return null;
using (foodorderingEntities dbContextOrderSet = new foodorderingEntities())
{
IEnumerable<CustomerOrder> resultsOneOrManyOrders = orders.Where(order => order.Number == myOrderNumber);
// you can replace the *** comparison with .string.Compare and try inside the block
return resultsOneOrManyOrders ;
}
}
I'm trying to run this simple query:
var appt = (from a in context.AppointmentSet
select new Appointment{ ModifiedOn = a.ModifiedOn}).First();
but I'm getting a compiler exception since ModifiedOn is readonly.
I could just return a, but then all the attributes of the Appointment entity will be returned, not just the ModifiedOn.
I could return new { a.ModifiedOn }, but then appt would be an AnonymousType and not an Appointment.
What's the suggested way to make this work?
Note, this is an example, assume that I'm returning more than just a single property from Appointment, and then there is a where criteria of some sort
I always do it like that:
var appt = (from a in context.AppointmentSet
select new Appointment {
Attributes =
{
{ "modifiedon", a.ModifiedOn },
{ "createdon", a.CreatedOn },
{ "createdby", a.CreatedBy }
}
})
.First();
It does not require any extra coding, I'm really surprised nobody posted that here yet.
This is the most efficient way I can think of:
Create a new constructor that accepts an AnonymousType (Object)
public Appointment(object anonymousType) : this()
{
foreach (var p in anonymousType.GetType().GetProperties())
{
var value = p.GetValue(anonymousType);
if (p.PropertyType == typeof(Guid))
{
// Type is Guid, must be Id
base.Id = (Guid)value;
Attributes["opportunityid"] = base.Id;
}
else if (p.Name == "FormattedValues")
{
// Add Support for FormattedValues
FormattedValues.AddRange((FormattedValueCollection)value);
}
else
{
Attributes[p.Name.ToLower()] = value;
}
}
}
Then call it like so:
var appt = (from a in context.AppointmentSet
select new Appointment(new { a.ModifiedOn })).First();
It has to reflect over all the properties of the AnoymousType, but it should work and has the added benefit of not having to rewrite the properties names each time.
I need to update all the properties of a given node, using mutating cypher. I want to move away from Node and NodeReference because I understand they are deprecated, so can't use IGraphClient.Update. I'm very new to mutating cypher. I'm writing in C#, using Neo4jclient as the interface to Neo4j.
I did the following code which updates the "Name" property of a "resunit" where property "UniqueId" equals 2. This works fine. However,
* my resunit object has many properties
* I don't know which properties have changed
* I'm trying to write code that will work with different types of objects (with different properties)
It was possible with IGraphClient.Update to pass in an entire object and it would take care of creating cypher that sets all properies.
Can I somehow pass in my object with mutating cypher as well?
The only alternative I can see is to reflect over the object to find all properties and generate .Set for each, which I'd like to avoid. Please tell me if I'm on the wrong track here.
string newName = "A welcoming home";
var query2 = agencyDataAccessor
.GetAgencyByKey(requestingUser.AgencyKey)
.Match("(agency)-[:HAS_RESUNIT_NODE]->(categoryResUnitNode)-[:THE_UNIT_NODE]->(resunit)")
.Where("resunit.UniqueId = {uniqueId}")
.WithParams(new { uniqueId = 2 })
.With("resunit")
.Set("resunit.Name = {residentialUnitName}")
.WithParams(new { residentialUnitName = newName });
query2.ExecuteWithoutResults();
It is indeed possible to pass an entire object! Below I have an object called Thing defined as such:
public class Thing
{
public int Id { get; set; }
public string Value { get; set; }
public DateTimeOffset Date { get; set; }
public int AnInt { get; set; }
}
Then the following code creates a new Thing and inserts it into the DB, then get's it back and updates it just by using one Set command:
Thing thing = new Thing{AnInt = 12, Date = new DateTimeOffset(DateTime.Now), Value = "Foo", Id = 1};
gc.Cypher
.Create("(n:Test {thingParam})")
.WithParam("thingParam", thing)
.ExecuteWithoutResults();
var thingRes = gc.Cypher.Match("(n:Test)").Where((Thing n) => n.Id == 1).Return(n => n.As<Thing>()).Results.Single();
Console.WriteLine("Found: {0},{1},{2},{3}", thingRes.Id, thingRes.Value, thingRes.AnInt, thingRes.Date);
thingRes.AnInt += 100;
thingRes.Value = "Bar";
thingRes.Date = thingRes.Date.AddMonths(1);
gc.Cypher
.Match("(n:Test)")
.Where((Thing n) => n.Id == 1)
.Set("n = {thingParam}")
.WithParam("thingParam", thingRes)
.ExecuteWithoutResults();
var thingRes2 = gc.Cypher.Match("(n:Test)").Where((Thing n) => n.Id == 1).Return(n => n.As<Thing>()).Results.Single();
Console.WriteLine("Found: {0},{1},{2},{3}", thingRes2.Id, thingRes2.Value, thingRes2.AnInt, thingRes2.Date);
Which gives:
Found: 1,Foo,12,2014-03-27 15:37:49 +00:00
Found: 1,Bar,112,2014-04-27 15:37:49 +00:00
All properties nicely updated!
I'm trying to create an audit log of any changes at point of save using Entity Framework. So far I have it working fairly well, storing all changes made to each field using the code below:
foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
{
// For updates, we only want to capture the columns that actually changed
if (!object.Equals(dbEntry.OriginalValues.GetValue<object>(propertyName), dbEntry.CurrentValues.GetValue<object>(propertyName)))
{
result.Add(new AuditLog()
{
UserID = UserId,
EventDateUTC = changeTime,
EventType = "M", // Modified
TableName = tableName,
RecordID = primaryKey.ToString(),
ColumnName = propertyName,
OriginalValue = dbEntry.OriginalValues.GetValue<object>(propertyName) == null ? null : dbEntry.OriginalValues.GetValue<object>(propertyName).ToString(),
NewValue = dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntry.CurrentValues.GetValue<object>(propertyName).ToString()
});
}
}
The issue I'm facing is how to get values for any foreign keys that belong to this object. For example: I have a vehicle object that has relationships to a series of lookup tables, such as gearbox, model etc. If these values change the audit table will store the changed id, but I want to store the actual value.
Is there a way of getting the foreign key value in this situation?
Alrighty... this is an old question but I've spent the last while working this out because I had the exact same requirements. Maybe there is an easier way, but here's the code I used:
Your original code, slightly modified for my purposes (RecordID is always an int), and calling the new method to calculate the new value
foreach (string propertyName in dbEntry.OriginalValues.PropertyNames)
{
// For updates, we only want to capture the columns that actually changed
if (!Equals(dbEntry.OriginalValues.GetValue<object>(propertyName), dbEntry.CurrentValues.GetValue<object>(propertyName)))
{
var newVal = getNewValueAsString(dbEntry, tableName, propertyName);
result.Add(new AuditLog
{
UserID = currentUser.ID,
Timestamp = changeTime,
EventType = EventType.Modified,
TableName = tableName,
RecordID = dbEntry.OriginalValues.GetValue<int>(keyName),
ColumnName = propertyName,
OriginalValue = dbEntry.OriginalValues.GetValue<object>(propertyName) == null ? null : dbEntry.OriginalValues.GetValue<object>(propertyName).ToString(),
NewValue = newVal
}
);
}
}
A new attribute called "IsName"
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class IsNameAttribute : Attribute
{
}
Marking the "name" property of foreign key models with the IsName attribute (note the code will default to a property called "Name" if it doesn't find one)
[Required]
[IsName]
public string Name { get; set; }
And the heavy lifting code
private string getNewValueAsString(DbEntityEntry dbEntry, string tableName, string propertyName)
{
var fkVal = getForeignKeyValue(tableName, propertyName, dbEntry.CurrentValues.GetValue<object>(propertyName));
return fkVal != null ? fkVal.ToString()
: (dbEntry.CurrentValues.GetValue<object>(propertyName) == null ? null
: dbEntry.CurrentValues.GetValue<object>(propertyName).ToString());
}
private object getForeignKeyValue(string tableName, string propertyName, object foreignKeyID)
{
// if this property is part of a foreign key, we need to instead look that up and store the value of the
// foreign key
// first get all the foreign keys in the system
var workspace = ((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace;
var items = workspace.GetItems<AssociationType>(DataSpace.CSpace);
if (items == null) return null;
var fk = items.Where(a => a.IsForeignKey).ToList();
// now we look into the FK attributes and find that the "To Role" is out current table, and the
// "To Property" is out current property. The underscore is a bit of an assumption that the foreign
// key name built by EF will be ENTITY_BLAH_BLAH
var thisFk = fk.Where(x => x.ReferentialConstraints[0].ToRole.Name.StartsWith(tableName + "_"))
.FirstOrDefault(x => x.ReferentialConstraints[0].ToProperties[0].Name == propertyName);
// if fkname has no results, this is not a foreign key and we are done
if (thisFk == null) return null;
// Now that we know the foriegn key, we need to lookup the Name value in the other table
// find the assembly
var assembly = Assembly.GetCallingAssembly();
// build the type for the foreign key entity
// e.g. if the current entity is Task, and the property is StatusID, we are
// getting the "TaskStatus" type with reflection
// "User" class is an object in the Models namespace - you could just hardcode the string if you want
var foreignKeyType = assembly.GetType(typeof(User).Namespace + "." +
thisFk.ReferentialConstraints[0].FromRole.GetEntityType().Name);
// get the DbSet, same as: "(new DBContext()).EntityName"
var fkSet = Set(foreignKeyType);
// and find the row in that table
var fkItem = fkSet.Find(foreignKeyID);
// find the first column marked with the "IsName" attribute, otherwise default to "Name"
var nameColProperty = foreignKeyType.GetProperties()
.FirstOrDefault(p => p.GetCustomAttributes(typeof(IsNameAttribute), false).Any());
string nameCol = "Name";
if (nameColProperty != null) nameCol = nameColProperty.Name;
var nameColProperty2 = fkItem.GetType().GetProperty(nameCol);
if (nameColProperty2 == null) return null;
// get the value
var fkValue = nameColProperty2.GetValue(fkItem, null);
// and now, my brain hurts
return fkValue;
}
This solution is based on #JamesR's answer.
My goal was to make the code more generic so it could be used for multiple foreign keys connecting to different tables.
Improvements worth noting:
I moved the code that gets the list of foreign keys outside of the propertyName foreach loop. Since the list of FKs doesn't change based on the specific property, there is no reason to retrieve a new list every time. If there are many FKs in the system, this can take a while, so you don't want to repeat the process unnecessarily.
Instead of hard-coding a specific class type like GetType(typeof(User), I retrieved the foreign key table name from the FK using:
string lookUpTableName = thisFk.ReferentialConstraints[0].FromRole.Name;
Then, although the referenced FK property name will usually be ID, since it can vary, I retrieved the FK property name as well:
string lookUpPropertyName = thisFk.ReferentialConstraints[0].FromProperties[0].Name;
I then used ObjectContext.ExecuteStoreQuery to dynamically plug in the table and column name and retrieve the foreign key text value.
If a property is a FK, I get the FK text value for both the original a new value.
Complete code:
First, get a list of all the foreign keys in the system.
IObjectContextAdapter contextAdapter = ((IObjectContextAdapter)this);
MetadataWorkspace workspace = contextAdapter.ObjectContext.MetadataWorkspace;
var items = workspace.GetItems<AssociationType>(DataSpace.CSpace);
List<AssociationType> FKList = items == null ? null
: items.Where(a => a.IsForeignKey).ToList();
Then, loop through the list of properties and replace the original and current values with the foreign key values when a FK exists.
foreach (string propertyName in entry.OriginalValues.PropertyNames)
{
var original = entry.OriginalValues.GetValue<object>(propertyName);
var current = entry.CurrentValues.GetValue<object>(propertyName);
if (FKList != null)
{
GetPossibleForeignKeyValues(tableName, propertyName, ref original, ref current,
FKList, contextAdapter);
}
if ((original == null && current != null) ||
(original != null && !original.Equals(current)))
{
result.Add(new AuditLog()
{
UserID = UserId,
EventDateUTC = changeTime,
EventType = "M", // Modified
TableName = tableName,
RecordID = primaryKey.ToString(),
ColumnName = propertyName,
OriginalValue = original != null ? original.ToString() : "NULL",
NewValue = current != null ? current.ToString() : "NULL"
});
}
}
Here is the actually foreign key finding code:
private void GetPossibleForeignKeyValues(string tableName, string propertyName,
ref object originalFKValue, ref object newFKValue,
List<AssociationType> FKList, IObjectContextAdapter contextAdapter)
{
// If this property is part of a foreign key, look up and set the FKValue to the text
// value of the foreign key. Otherwise, just leave the FKValue alone.
// Look into the FK attributes and find that the "To Role" is out current table,
// and the "To Property" is out current property.
AssociationType thisFk = FKList.FirstOrDefault(x =>
tableName.Contains(x.ReferentialConstraints[0].ToRole.Name)
&& propertyName.Contains(x.ReferentialConstraints[0].ToProperties[0].Name));
// If fkname has no results, this is not a foreign key and we are done.
if (thisFk != null)
{
// Now that we know the foriegn key, look up the Name value in the other table.
string lookUpTableName = thisFk.ReferentialConstraints[0].FromRole.Name;
string lookUpPropertyName = thisFk.ReferentialConstraints[0].FromProperties[0].Name;
//Assuming the FK column name is "Name".
//Use the idea in #JamesR's solution or some sort of LookUp table if it is not.
string commandText = BuildCommandText("Name", lookUpTableName, lookUpPropertyName);
originalFKValue = contextAdapter.ObjectContext
.ExecuteStoreQuery<string>(commandText, new SqlParameter("FKID", originalFKValue))
.FirstOrDefault() ?? originalFKValue;
newFKValue = contextAdapter.ObjectContext
.ExecuteStoreQuery<string>(commandText, new SqlParameter("FKID", newFKValue))
.FirstOrDefault() ?? originalFKValue;
}
}
This is the method I used to build the SQL CommandText:
private string BuildCommandText(string columnName, string lookUpTableName,
string lookUpPropertyName)
{
StringBuilder builder = new StringBuilder();
builder.Append("SELECT ");
builder.Append(columnName);
builder.Append(" FROM ");
builder.Append(lookUpTableName);
builder.Append(" WHERE ");
builder.Append(lookUpPropertyName);
builder.Append(" = #FKID");
//The result query will look something like:
//SELECT ColumnName FROM TableName WHERE PropertyName = #FKID
return builder.ToString();
}
I have a many to many relationship between Contractors and SafetyCouncils. They are joined by a bridge table ContractorsSafetyCouncils which consists of ContractorId and SafetyCouncilId. These 2 columns form a composite key. This relationship is mapped correctly in EF4. The Contractor entity has the property:
public virtual ICollection<SafetyCouncil> SafetyCouncils
{
get;
set;
}
And the SafetyCouncil entity has the property:
public virtual ICollection<Contractor> Contractors
{
get;
set;
}
When accessing these properties via lazy loading from a single Contractor or SafetyCouncil entity, they work exactly as expected. But when accessing this relationship in a query:
from c in ContractorRepository.All()
where c.PQFs.Count() > 0
let psmAudits = c.PQFs.SelectMany(pqf => pqf.Audits)
let psmAudit = psmAudits.FirstOrDefault(audit => audit.CompletedDate == psmAudits.Max(a => a.CompletedDate))
let scsAudits = c.PQFs.SelectMany(pqf => pqf.SCSAudits)
let scsAudit = scsAudits.FirstOrDefault(audit => audit.CompletedDate == scsAudits.Max(a => a.CompletedDate))
select new MasterListItem()
{
AdministratorNotes = c.AdminFlags.Where(f => f.IsActive && f.ForPQF).Select(f => f.Text),
CanViewInfo = false,
ContractorName = c.ContractorName,
ContractorId = c.Id,
ContractorTaxId = c.TaxId,
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
PQFSubmitted = c.PQFs.Max(p => p.PQFInfo.SubmittedDate.Value),
PSMAuditId = psmAudit.Id,
PSMAuditComplete = psmAudit.CompletedDate,
PSMAuditStatus = psmAudit.Status.Description,
SCSAuditId = scsAudit.Id,
SCSAuditComplete = scsAudit.CompletedDate
};
The problem occurs with:
SafetyCouncilIds = c.SafetyCouncils.Select(sc => sc.Id),
For every record the SafetyCouncilIds collection has 0 members, when based on the data in the database every record should have at least 1 SafetyCouncilId associated with it.
If I run the same query, but project into an anonymous type instead of the MasterListItem type, it works correctly. Why can't I project this query into my custom type?
Update:
My MasterListItem POCO contained the following properties:
public string SafetyCouncilIdsString
{
get;
set;
}
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb.Append(id);
sb.Append(",");
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.
public IEnumerable<int> SafetyCouncilIds
{
set
{
StringBuilder sb = new StringBuilder(",");
foreach (var id in value)
{
sb = sb.Append(id).Append(","); // <-- try this
// *or sb = sb.AppendFormat("{0},", id);*
}
this.SafetyCouncilIdsString = sb.ToString();
}
}
I have two suggestions:
Try to isolate the the problem by removing any extra parts of the query.
Compare the two sql queries generated and find the differences.
Unfortunately, without access to your code or schema, I can't provide a better answer.
The SafetyCouncilIds property was the cause of the problem. I changed this to an automatic property and built the string elsewhere and projecting onto the POCO worked like a charm.