How can I set parent-child relation on same table using ActiveRecord? - parentid

How can I set parent-child relation on same table?
Id int,
title string,
ParentId int ---> this is refer to Id

What ActiveRecord implementation are you using?
In Castle ActiveRecord, if your table looked like this:
table Document (
Id int primary key,
ParentDocumentId int,
Title string
)
you'd use the following syntax:
[ActiveRecord(Table = "Document")]
public class Document : ActiveRecordBase<Document> {
private int id;
private Document parent;
private string title;
private List<Document> children = new List<Document>();
[PrimaryKey]
public int Id {
get { return id; }
set { id = value; }
}
[BelongsTo("ParentDocumentId")]
public virtual Document Parent {
get { return parent; }
set { parent = value; }
}
[HasMany(Table = "Document", ColumnKey = "ParentDocumentId", Inverse = true, Cascade = ManyRelationCascadeEnum.All)]
public IList<Document> Children {
get { return children.AsReadOnly(); }
private set { children = new List<Document>(value); }
}
[Property]
public string Title {
get { return title; }
set { title = value; }
}
}

Related

Dynamically attach entry to context

I am using .Net 4.5 and Entity Framework 6 to create a REST Web API.
In my Update methods I need to attach the object recieved in the web api, back to the dbcontext. I have achieved this using the code below. What I want to do now, is to make this code reusable so that I can call AttachToContext for any object in the model.
I understand that I have to use generic type T and TEntity, but I cannot find any suitable examples.
//Repository.cs
public void UpdateOrderItem(OrderItem orderItem)
{
try
{
AttachToContext(orderItem);
_context.SaveChanges();
}
catch (Exception e)
{
}
}
private void AttachToContext(OrderItem orderItem)
{
var entry = _context.Entry<OrderItem>(orderItem);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity(orderItem.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, orderItem);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private OrderItem FindExistingEntity(int id)
{
var set = _context.Set<OrderItem>();
return set.Find(id);
}
private void UpdateEntityValues(OrderItem existing, OrderItem updated)
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
private bool EntityExists(object entity)
{
return entity != null;
}
Your AttachToContext has dependency to primary key property, orderItem.Id, to change it into dynamic, you can introduce an interface and implement to all entities you have or just passing the id as parameters.
Interface
public interface IEntity
{
public int Id { get; set; }
}
public class OrderItem : IEntity
{
// body
}
Then modify the AttachToContext as follow.
private void AttachToContext<T>(T entity) where T : class, IEntity
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(entity.Id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(int id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem);.
Passing The Keys
private void AttachToContext<T>(T entity, params object[] id) where T : class
{
var entry = _context.Entry(entity);
if (entry.State == EntityState.Detached)
{
var attachedEntity = FindExistingEntity<T>(id);
if (EntityExists(attachedEntity))
{
UpdateEntityValues(attachedEntity, entity);
}
else
{
entry.State = EntityState.Modified;
}
}
}
private T FindExistingEntity<T>(object[] id) where T : class
{
var set = _context.Set<T>();
return set.Find(id);
}
private void UpdateEntityValues<T>(T existing, T updated) where T : class
{
var attachedEntry = _context.Entry(existing);
attachedEntry.CurrentValues.SetValues(updated);
}
The usage would be AttachToContext(orderItem, orderItem.Id);.
Another alternative would be using object set to get the primary key properties, then using reflection to get the value. To get the primary key properties has been explained in this post.

WPF listbox binding to listview

I have below classes:
public class BusinessFunction
{
private string str_Id;
public string id
{
get { return str_Id; }
set { str_Id = value; }
}
private List<Function> str_FunctionList;
public BusinessFunction() { }
public List<Function> functionList
{
get { return str_FunctionList; }
set { str_FunctionList = value; }
}
}
public class Function
{
private string str_FunctionType;
public string functionType
{
get { return str_FunctionType; }
set { str_FunctionType = value; }
}
private string str_FunctionName;
public string functionName
{
get { return str_FunctionName; }
set { str_FunctionName = value; }
}
private string str_Value;
public string value
{
get { return str_Value; }
set { str_Value = value; }
}
}
I have to bind the above data into Listbox and Listview. The "id" should display in listbox and the "functionList" in listview. When user changes the selection in listbox, it should bring the associated "functionList" into listview.
How to achieve this scenario?
Thanks
Listview Itemsource={Binding functionList} did the trick.

How to retrieve an object's Property name/value pairs on a custom object?

I have a custom object with varying datatypes for each property.
I would like to be able to do something like:
public void evalCI(configurationItem CI)
{
foreach (PropertyInformation n in CI)
{
Response.Write(n.Name.ToString() + ": " + n.Value.ToString() + "</br>");
}
}
My custom object is:
public class configurationItem : IEnumerable
{
private string serial;
private string model;
private DateTime? wstart;
private DateTime? wend;
private Int32 daysLeft;
private string platform;
private string productVersion;
private string manufacturer;
private bool verificationFlag;
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public string Serial
{
set { serial = value; }
get { return serial; }
}
public string Model
{
set { model = value; }
get { return model; }
}
public DateTime? Wstart
{
set { wstart = value; }
get { return wstart; }
}
public DateTime? Wend
{
set { wend = value; }
get { return wend; }
}
public Int32 DaysLeft
{
set { daysLeft = value; }
get { return daysLeft; }
}
public string Platform
{
set { platform = value; }
get { return platform; }
}
public string ProductVersion
{
set { productVersion = value; }
get { return productVersion; }
}
public string Manufacturer
{
set { manufacturer = value; }
get { return manufacturer; }
}
public bool VerificationFlag
{
set { verificationFlag = value; }
get { return verificationFlag; }
}
My expected output would be:
-Serial: 1234567
-Model: Mustang
-Wstart: 12/12/2005
-Wend: 12/11/2006
-DaysLeft: 0
-Platform: Car
-ProductVersion: GT
-Manufacturer: Ford
-VerificationFlag: true
At first I was getting an error that GetEnumerator() had to be implemented to use a foreach loop. The problem I keep running into is that all of the examples of Indexed Properties are of a single property with an indexable list, instead of an index for each property in the object. I was able to get intellisense to give me methods for PropertyInfo by adding:
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
However, the 2nd GetEnumerator() throws:
Compiler Error Message: CS0103: The name 'GetEnumerator' does not exist in the current context.
What am I missing here? How do I modify my object to give me the results I expect from evalCI()?
You don't need to implement IEnumerable. What you do need to do is use Reflection.
This is from memory, but I believe it would look like this:
foreach (PropertyInfo n in typeof(configurationItem).GetProperties())
{
Response.Write(string.Format("{0}: {1}<br/>", n.Name, n.GetValue(CI, null)));
}
This - the code as written - will also only give you public properties, and non-indexed properties (but it doesn't look like you have any indexed properties).

Steps to map classes using ValueInjector

Quickly getting to the problem the mapping does not occur for the following code. Could someone explain why? or what i should do for the mapping to occur?
var parent = new Parent();
parent.ChildOne.Add(new ChildOne() { Name = "Child One" });
parent.ChildTwo.Add(new ChildTwo() { Name = "Child Two" });
AnotherParent anotherParent = new AnotherParent();
anotherParent.InjectFrom<LoopValueInjection>(parent);
Required Class are below
Anothher child one
public class AnotherChildOne
{
public string Name { get; set; }
}
Another child two
public class AnotherChildTwo
{
public string Name { get; set; }
}
Another Parent
public class AnotherParent
{
public ICollection<AnotherChildOne> ChildOne { get; set; }
public ICollection<AnotherChildTwo> ChildTwo { get; set; }
public AnotherParent()
{
ChildOne = new Collection<AnotherChildOne>();
ChildTwo = new Collection<AnotherChildTwo>();
}
}
Child Two
public class ChildTwo
{
public string Name { get; set; }
}
Child One
public class ChildOne
{
public string Name { get; set; }
}
Parent
public class Parent
{
public ICollection<ChildOne> ChildOne { get; set; }
public ICollection<ChildTwo> ChildTwo { get; set; }
public Parent()
{
ChildOne = new Collection<ChildOne>();
ChildTwo = new Collection<ChildTwo>();
}
}
I believe by default Value Injector will only inject the properties with the same name of the same type. You can get around this using a tweak to the CloneInjection sample from the Value Injector documentation as described here with this code:
public class CloneInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name && c.SourceProp.Value != null;
}
protected override object SetValue(ConventionInfo c)
{
//for value types and string just return the value as is
if (c.SourceProp.Type.IsValueType || c.SourceProp.Type == typeof(string)
|| c.TargetProp.Type.IsValueType || c.TargetProp.Type == typeof(string))
return c.SourceProp.Value;
//handle arrays
if (c.SourceProp.Type.IsArray)
{
var arr = c.SourceProp.Value as Array;
var clone = Activator.CreateInstance(c.TargetProp.Type, arr.Length) as Array;
for (int index = 0; index < arr.Length; index++)
{
var a = arr.GetValue(index);
if (a.GetType().IsValueType || a.GetType() == typeof(string)) continue;
clone.SetValue(Activator.CreateInstance(c.TargetProp.Type.GetElementType()).InjectFrom<CloneInjection>(a), index);
}
return clone;
}
if (c.SourceProp.Type.IsGenericType)
{
//handle IEnumerable<> also ICollection<> IList<> List<>
if (c.SourceProp.Type.GetGenericTypeDefinition().GetInterfaces().Contains(typeof(IEnumerable)))
{
var t = c.TargetProp.Type.GetGenericArguments()[0];
if (t.IsValueType || t == typeof(string)) return c.SourceProp.Value;
var tlist = typeof(List<>).MakeGenericType(t);
var list = Activator.CreateInstance(tlist);
var addMethod = tlist.GetMethod("Add");
foreach (var o in c.SourceProp.Value as IEnumerable)
{
var e = Activator.CreateInstance(t).InjectFrom<CloneInjection>(o);
addMethod.Invoke(list, new[] { e }); // in 4.0 you can use dynamic and just do list.Add(e);
}
return list;
}
//unhandled generic type, you could also return null or throw
return c.SourceProp.Value;
}
//for simple object types create a new instace and apply the clone injection on it
return Activator.CreateInstance(c.TargetProp.Type)
.InjectFrom<CloneInjection>(c.SourceProp.Value);
}
}
If you include the above CloneInjection code you will want to do this:
anotherParent.InjectFrom<CloneInjection>(parent);
instead of:
anotherParent.InjectFrom<LoopValueInjection>(parent);

Turning objects DataSource to a List<>

Attempting to take the data in my gridview and convert it back into a list so I can run an update function. Currently I'm getting a null value when I attempt this.
List<CodeEntity> codes = new List<CodeEntity>();
codes = (List<CodeEntity>)Convert.ChangeType(gdvFGCode.DataSource,typeof(List<CodeEntity>));
Response.Write(codes[0].FGCode);
Also, Since the Gridview contains 3 template fields all with controls inside, would the datasource returned contain the updated values from the controls or would it return the original List<> pasted into it.
EDIT: The class I'm attempting to return in the list
public class CodeEntity
{
private string _fgCode;
private Int16 _palletSet;
private bool _priority;
private int _codeState;
private string _formingCode;
private string _d4Code;
public string FGCode
{
get { return _fgCode; }
set { _fgCode = value; }
}
public int CodeState
{
get { return _codeState; }
set { _codeState = value; }
}
public Int16 PalletSet
{
get { return _palletSet; }
set { _palletSet = value; }
}
public bool Priority
{
get { return _priority; }
set { _priority = value; }
}
public string FormingCode
{
get { return _formingCode; }
set { _formingCode = value; }
}
public string D4Code
{
get { return _d4Code; }
set { _d4Code = value; }
}
}
I would think the following should work:
if (gdvFGCode.DataSource != null)
{
List<CodeEntity> codes = (List<CodeEntity>)gdvFGCode.DataSource;
}
Edit
Added null check on the Datasource and updated code to accurately reflect OP's code.

Resources