Extracting a complex type from entry.CurrentValues - entity-framework-5

Some of my domain classes contain a complex type for a street address.
I am capturing a log of my changes, and want to be able to reconstruct the address object from the ObjectStateEntry.CurrentValues
My code is detailed here
And I want to extract the address from CurrentValues as the answer suggests.
I can see the address in the _userObject property in the debugger, but i don't know how to extract it.
I have tried
var obj = entry.CurrentValues[ordinal];
var rec = (DbDataRecord)obj;
what should be next?

public static T ConvertTo<T>(this DbDataRecord record)
{
T item = Activator.CreateInstance<T>();
for (int f = 0; f < record.FieldCount; f++)
{
var p = item.GetType().GetProperty(record.GetName(f));
if (p != null && p.PropertyType == record.GetFieldType(f))
{
p.SetValue(item, record.GetValue(f), null);
}
}
return item;
}

Related

How to get Opportunity Relations in Sales Order

In Opportunity screen, the definition of the data view for Relations is simply :
public CRRelationsList<CROpportunity.noteID> Relations;
When a Sales Order is raised from the Opportunity. I'd like to display the Relations defined from the source Opporunity in another tab. And I'm just struggling how to write the the data view and pass the Opportunity noteid.
public CRRelationsList<???>Relations;
Thanks !
The generic type in dataviews often resolve to the current record.
In CRRelationsList class the generic type is named TNoteField:
public class CRRelationsList<TNoteField> : PXSelect<CRRelation>
where TNoteField : IBqlField
ssuming the dataview is declared as CRRelationsList<CROpportunity.noteID>.
The generic type value will be resolved like this Caches[typeof(CROpportunity)].Current.NoteID.
protected virtual void CRRelation_RefNoteID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
// Get a cache object of type CROpportunity
var refCache = sender.Graph.Caches[BqlCommand.GetItemType(typeof(TNoteField))];
// Get the NoteID field value of the current CROpportunity object
e.NewValue = refCache.GetValue(refCache.Current, typeof(TNoteField).Name);
}
So to set DAC.Field of CRelationsList<DAC.field> you would do:
// In a graph extension (PXGraphExtension)
Base.Caches[typeof(DAC)].Current.Fied = ???;
// Or in graph (PXGraph)
Caches[typeof(DAC)].Current.Fied = ???;
If current DAC object is null you need to insert a record in a dataview or directly in the cache object.
I'm not sure re-using CRRelationsList list is the best approach if you want to simply display records because it does much more than that. It should be possible to extract the select request out of it and directly substitute the TNoteField value:
private static PXSelectDelegate GetHandler()
{
return () =>
{
var command = new Select2<CRRelation,
LeftJoin<BAccount, On<BAccount.bAccountID, Equal<CRRelation.entityID>>,
LeftJoin<Contact,
On<Contact.contactID, Equal<Switch<Case<Where<BAccount.type, Equal<BAccountType.employeeType>>, BAccount.defContactID>, CRRelation.contactID>>>,
LeftJoin<Users, On<Users.pKID, Equal<Contact.userID>>>>>,
Where<CRRelation.refNoteID, Equal<Current<TNoteField>>>>();
var startRow = PXView.StartRow;
int totalRows = 0;
var list = new PXView(PXView.CurrentGraph, false, command).
Select(null, null, PXView.Searches, PXView.SortColumns, PXView.Descendings, PXView.Filters,
ref startRow, PXView.MaximumRows, ref totalRows);
PXView.StartRow = 0;
foreach (PXResult<CRRelation, BAccount, Contact, Users> row in list)
{
var relation = (CRRelation)row[typeof(CRRelation)];
var account = (BAccount)row[typeof(BAccount)];
relation.Name = account.AcctName;
relation.EntityCD = account.AcctCD;
var contact = (Contact)row[typeof(Contact)];
if (contact.ContactID == null && relation.ContactID != null &&
account.Type != BAccountType.EmployeeType)
{
var directContact = (Contact)PXSelect<Contact>.
Search<Contact.contactID>(PXView.CurrentGraph, relation.ContactID);
if (directContact != null) contact = directContact;
}
relation.Email = contact.EMail;
var user = (Users)row[typeof(Users)];
if (account.Type != BAccountType.EmployeeType)
relation.ContactName = contact.DisplayName;
else
{
if (string.IsNullOrEmpty(relation.Name))
relation.Name = user.FullName;
if (string.IsNullOrEmpty(relation.Email))
relation.Email = user.Email;
}
}
return list;
};
}

How do I get an object from an observable item Collection by index?

I need to get the object in an observable collection by index to access a property of the item at that index.
This is a snippet of the code:
public ObservableCollection<TipsModel> TipObjects;
private void LoadContent()
{
TipObjects = new ObservableCollection<TipsModel>();
for (int i = 0; i < 5; i++)
{
TipsModel item = new TipsModel()
{
Image = ImageSource.FromFile("nonindustryIcon.png"),
Title = "Kill energy vampires and save up to $100 a year",
Text = "Seventy-five percentof the electrical use by home electronics occurs when they're at home. \n People not at home means no electricity. Do not stay at home. Go stay on the streets. ",
};
TipObjects.Add(item);
}
foreach (TipsModel item in TipObjects)
{
img = item.Image;
tipTitle = item.Title;
tip = item.Text;
item.Content = CreateContent();
}
slideView.ItemsSource = TipObjects;
}
private void slideView_SlidedToIndex(object sender, Telerik.XamarinForms.Primitives.SlideView.SlideViewSlidedToIndexEventArgs e)
{
var slideId = slideView.Id;
//TipsModel tip = TipObjects.item at index[18];
}
You can just normally do
var tip = TipObjects[18];
Observable collection is just a normal, fully functional collection that supports indexing.
Alternatively you can use the Items property as well. Both approaches are equivalent:
var tip = TipObjects.Items[18];

Groovy - String each method

I have just started learning Groovy which looks really awesome!
This is very simple example.
"Groovy".each {a -> println a};
It nicely prints as given below.
G
r
o
o
v
y
My question is - 'each' method is not part of String object as per the link below. Then how come it works?
http://beta.groovy-lang.org/docs/latest/html/groovy-jdk/
How can i get the parameters list for a closure of an object?
example String.each has 1 parameter, Map.each has 1 or 2 parameters like entry or key & value.
The relevant code in DefaultGroovyMethods is
public static Iterator iterator(Object o) {
return DefaultTypeTransformation.asCollection(o).iterator();
}
which contains:
else if (value instanceof String) {
return StringGroovyMethods.toList((String) value);
}
String toList is:
public static List<String> toList(String self) {
int size = self.length();
List<String> answer = new ArrayList<String>(size);
for (int i = 0; i < size; i++) {
answer.add(self.substring(i, i + 1));
}
return answer;
}

Verify if two lists share values in C#

I'd like to know if two lists share values before applying an intersection. Something like bool DoIntersect(listA, listB) would be fabulous!
This is the code I came up with:
// Person is a class with Id and Name properties
List<Person> people1;
List<Person> people2;
// Populate people1 and people2...
// My current solution (pseudocode obviously)...
if (DoIntersect(people1, people2))
{
people1 = people1.Intersect(people2)
}
else
{
/* No shared people */
throw exception;
}
// Continue with the process...
It depends on exactly what you want:
// are there any common values between a and b?
public static bool SharesAnyValueWith<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
return a.Intersect(b).Any();
}
For lists that don't overlap, this will iterate through a and b each once. For lists that overlap, this will iterate all the way through a, then through b until the first overlapping element is found.
// does a contain all of b? (ignores duplicates)
public static bool ContainsAllFrom<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
return !b.Except(a).Any();
}
This will iterate through a once, then will iterate through b, stopping on the first element in b not in a.
// does a contain all of b? (considers duplicates)
public static bool ContainsAllFrom<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
// get the count of each distinct element in a
var counts = a.GroupBy(t => t).ToDictionary(g => g.Key, g => g.Count());
foreach (var t in b) {
int count;
// if t isn't in a or has too few occurrences return false. Otherwise, reduce
// the count by 1
if (!counts.TryGetValue(t, out count) || count == 0) { return false; }
counts[t] = count - 1;
}
return true;
}
Similarly, this will iterate through a once, then will iterate through b, stopping on the first element in b not in a.
I believe without altering the fact that you're using a List you can't get better performance.
However, if you would have 2 sorted lists to begin with (requires overhead when creating them), then you could iterate through them with complexity of O(n) in order to find out if you have shared values.
Edit:
Although original OP doesn't have 2 sorted lists, in case someone will need it, here is the implementation for checking Intersection at O(n):
public Boolean DoIntersect(SortedList<int,String> listA,SortedList<int,String> listB )
{
if (listA == null || listA.Count == 0 || listB == null || listB.Count == 0)
{
return false;
}
var keysA = listA.Keys;
var keysB = listB.Keys;
int i = 0, j = 0;
while (i < listA.Count && j < listB.Count)
{
if (keysA[i] < keysB[j])
{
i++;
}else if (keysA[i] > keysB[j])
{
j++;
}
else
{
return true;
}
}
The above approach can be used also with IEnumerable lists, given that they are sorted, with slight variation - using GetEnumerator and iterating with it.

Mapping umbraco node to strongtyped object

I am working with Umbraco 4.7.1 and I am trying to map the content-nodes to some autogenerated strong typed objects. I have tried using both valueinjecter and automapper, but OOTB neither of them map my properties. I guess it is because all properties on an Umbraco node (the cms document) are retrieved like this:
node.GetProperty("propertyName").Value;
And my strongly typed objects are in the format of MyObject.PropertyName. So how do I map the property on the node which is retrieved using a method and a string beginning with a lowercase character into a property on MyObject where the property begins with an uppercase character ?
UPDATE
I managed to create the following code which maps the umbraco node as intended, by digging around in the Umbraco sourcecode for some inspiration on how to cast string-properties to strongly typed properties:
public class UmbracoInjection : SmartConventionInjection
{
protected override bool Match(SmartConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name;
}
protected override void Inject(object source, object target)
{
if (source != null && target != null)
{
Node node = source as Node;
var props = target.GetProps();
var properties = node.Properties;
for (int i = 0; i < props.Count; i++)
{
var targetProperty = props[i];
var sourceProperty = properties[targetProperty.Name];
if (sourceProperty != null && !string.IsNullOrWhiteSpace(sourceProperty.Value))
{
var value = sourceProperty.Value;
var type = targetProperty.PropertyType;
if (targetProperty.PropertyType.IsValueType && targetProperty.PropertyType.GetGenericArguments().Length > 0 && typeof(Nullable<>).IsAssignableFrom(targetProperty.PropertyType.GetGenericTypeDefinition()))
{
type = type.GetGenericArguments()[0];
}
targetProperty.SetValue(target, Convert.ChangeType(value, type));
}
}
}
}
}
As you can see I use the SmartConventionInjection to speed things up.
It still takes approximately 20 seconds to map something like 16000 objects. Can this be done even faster ?
thanks
Thomas
with ValueInjecter you would do something like this:
public class Um : ValueInjection
{
protected override void Inject(object source, object target)
{
var node = target as Node;
var props = source.GetProps();
for (int i = 0; i < props.Count; i++)
{
var prop = props[i];
target.GetProperty(prop.Name).Value;
}
}
}

Resources