Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
If I have a class which represent a mapping to a specific table in my db in somehow.
This class contains about 30 properties.
I have created the CRUD Methods.
And find myself need to another (UPDATE) method which should update just two fields.
What should I do in a good manner with simple example?
Using my exist method, Filling the whole object and update all the fields including my intended two fields? (Useless work)
Create static Method with another name (but I want to keep my method name because it's expressive)! And takes two parameters?
I would go by by creating two separate interface and create overloaded functions for each interface. I would group properties based on usage, like I want status to be updated some time separate from other common properties.
public interface ICommonProperties
{
public string P1{get; set;}
public string P2{get; set;}
public string P3{ get; set; }
}
public interface ITrackable
{
public string Status{get; set;}
}
public class FinalClass : ICommonProperties, ITrackable
{
public string P1{get; set;}
public string P2{get; set;}
public string P3{get; set;}
public string Status{get; set;}
}
public class FinalClassOperations
{
public void Update(FinalClass finalClassInstance) { }; //Updates everything
public void Update(ICommonProperties finalClassInstance) { }; //Updates only ICommonProperties
public void Update(ITrackable finalClassInstance) { }; //updates only Status.
}
Additionally, if you want you can create a separate class for just updating the status, and that would still fit in:
public class Tracker : ITrackable{
public string Status{get; set;}
}
But yes, if the two properties cannot be separated out logically, I would not do that and keep them together.
I would suggest to follow your second option but there is no need to change the name as the number of method parameter will be different on both it's
Let's as walk into few example
I will try to create an similar situation, I hope it's your situation. you can clarify if i got wrongly the question.
CLASSES AND METHOD
/// <summary>
/// CLass to store properties related to database
/// </summary>
class ObjectoA
{
public string A{get; set;}
public string B{get; set;}
public string C{ get; set; }
}
/// <summary>
/// class to call method to update.
///
/// </summary>
class ObjectB
{
/// <summary>
/// update method.
/// I would go with this solution.
/// optionlay you can call the method which receive parameter of object
/// </summary>
/// <param name="A"> Object with properties mapped to database</param>
/// <param name="updatetwoproperties">Optional paramneter to decide which update to run.
/// the default value should be for update that run most. For your need if you want to create an update methods for other
/// two sets of parameter a suggest you create an Enum and pass this enum as optional parameter instead of bool parameter or you
/// can pass as string and map each string value to specific update inside. IF YOU NEED EXAMPLE
/// REPLAY ON COMMENTS</param>
/// <returns></returns>
public bool update(ObjectoA A, bool updatetwoproperties=false)
{
//method implementation
if (updatetwoproperties)
{
//implement a update to all field
}
else
{
//implement update just to two field
}
return true;
}
/// <summary>
/// update method based on parameter to update
/// </summary>
/// <param name="a">this properties is mapped on database</param>
/// <param name="b">this propertie is mapped on database</param>
/// <returns></returns>
public bool update(string a, string b)
{
//method implementation e validate the return value
return true;
}
}
/// <summary>
/// I don't suggest to use this solution because
/// it will add a method on string type while this method isn't related to string
/// I just added here as a workaround for you.
/// </summary>
public static class ObjectC
{
public static bool update(this string a, string b)
{
//implementation of update and validate the return value
return true;
}
}
CALLING METHOD AND EXPLANATION
static void Main(string[] args)
{
ObjectB B = new ObjectB(); //Class with methods
ObjectoA A = new ObjectoA(); //object with properties
#region Using Optional parameter to decide which update to run
//Calling a method to update all columns
B.update(A);
//Calling a method to update two columns
B.update(A, true);
#endregion
#region Using polymorphism to update
//Calling a method to update all columns
B.update(A);
//Update only using paramenter
B.update(A.B, A.C);
#endregion
//NOT RECOMMEND BECAUSE THIS UPDATE ISN'T RELATED TO STRING TYPE
#region Using extension method to update
//Calling a method to update all columns
B.update(A);
//using the extension method on variable type
A.B.update(A.C);
#endregion
//WE COULD USE EXTENSION METHOD ON YOUR OBJECT BUT IT WILL FAIL BECAUSE WE ALREADY AS UPDATE METHOD ON CLASS
//IF YOU WANT TO SEE HOW JUST REPLAY
}
I SUGGEST YOU ADD OPTIONAL PARAMETER ON YOUR METHOD TO DECIDE WHICH UPDATE TO USE
It depends on what your priorities are on the project:
using your already existing update method is gonna update everything all the time, incressing traffic, IO and process time (validation and so on...)
If you're on a project where properties are timestamped, they would be updated even if the value hasn't really changed...
If you don't mind about all this, use your update() method all the time.
My personnal POV is: create a new method (with an explicit name). This will same process time from now on and thinking time in 2 years when you'll have to change this class ;)
I don't know if this is what you should do necessarily, but here's something you could do: Create a SetAll or SetMany or whatever method where you pass in another instance of your class (source). Check each property and if it's non-null, you set the destination object's property value to the source object's property value. Note that this tactic will depend on nullable types, and assumes you can ignore null values passed into a new setter method. Here's an illustration:
using System;
namespace BlogPartialUpdateTrick
{
public class SomeClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int? HeightInches { get; set; }
public DateTime? Dob { get; set; }
public void SetAll(SomeClass source)
{
this.FirstName = source.FirstName ?? this.FirstName;
this.LastName = source.LastName ?? this.LastName;
this.HeightInches = source.HeightInches ?? this.HeightInches;
this.Dob = source.Dob ?? this.Dob;
}
public override string ToString()
{
return String.Format("fn: {0}, ln: {1}, height: {2}, DOB: {3}", FirstName ?? String.Empty, LastName ?? String.Empty,
HeightInches.HasValue ? HeightInches.Value.ToString() : "null", Dob.HasValue ? Dob.Value.ToShortDateString() : "null" );
}
}
}
In this first code sample, We have my spiffy class SomeClass. It's got 4 properties, all of which are nullable. The noteworthy part of this class is the SetAllMethod where I can pass in a source object which is also of type SomeClass. It sets this instance's property values to the values passed in the source parameter, but only if they're non-null. Here's a 2nd code blurb where I'm using this stuff:
using System;
using System.Windows.Forms;
namespace BlogPartialUpdateTrick
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var destination = new SomeClass() { FirstName = "Freddy", LastName = "Fingers", Dob = DateTime.Parse("01/01/1970"), HeightInches = 72 };
var source = new SomeClass() { FirstName = null, LastName="Flippers", Dob = null, HeightInches = 80 };
destination.SetAll(source);
MessageBox.Show(destination.ToString());
}
}
}
Create a destination object, a source object, call the new method, voila! output is this:
"fn: Freddy, ln: Flippers, height: 80, DOB: 1/1/1970"
You should probably use Entity Framework and let the context do it for you. Using EF, you'll be able to update Entities like this :
try
{
var original = ObjectContext.Set<Request>().SingleOrDefault(x => x.Id.Equals(_request.Id));
if (original != null)
{
ObjectContext.Entry(original).CurrentValues.SetValues(_request);
}
return ObjectContext.SaveChanges();
}
catch (Exception ee)
{
return -1;
}
Related
We are planning a pretty big application.
-We want to internationalize our application for 30 countries.
-In most countries 1 to 6 different brands are available.
-Each combination of a certain locale like 'de' and brand like 'XXX' might occur multiple times therefore we need another identifier to get something unique:
"locale_brand_siteorigin"
Therefore we have .resx file like:
Configurations.de.burgerking.px10.resx
The bold printed is the unique identifier.
During runtime we create a:
var rm = new ResourceManager("MyNamespace.Configurations.UniqueIdentifier",Assembly.GetExecuting());
Depending on our business logic we can create the above resourceManager.
Finally we will end up having 180+ resx files with all combinations of the unique identifier.
Do you know of a better way to do this kind of branding?
4 years ago someone asked this question, but none answered:
Industry standard for implementing application branding?
UPDATE
I also want to extend my question asking for a solution showing the benefits of using the cultureandregioninfobuilder class to create those many custom cultures.
https://msdn.microsoft.com/en-us/library/system.globalization.cultureandregioninfobuilder(v=vs.110).aspx
I wouldn't recommend using .resx files for such a huge project. When a website is translated in many different languages, usually a lot of people are involved in the copy management, translation etc. These people will not be able to edit the .resx files since they are technically embedded in the application code. This means that your developers will have to constantly update the resources every time there are changes... a real nightmare for everybody.
I recently build a database-driven system for the SumoSoft.Cms. All the strings can be managed through the Admin panel, while in the code you just use:
#CmsMethods.StringContent("ContentSection_Name", "Fallback_Value")
This Helper queries the Database looking for an entity of Type "ContentSection" which is structured more or less like this:
public class ContentSection
{
public string Name { get; set; }
public ICollection<ContentSectionLocalizedString> LocalizedStrings { get; set; }
}
Each LocalizedString contains a reference to a specific Country and a property "Content", so all the Helper does is to choose the one that matches the Current Culture of the Thread.
Expanding on #FrancescoLorenzetti84 answer, one way I've done it in the past to make it easier to maintain is to wrap the database retrieval in a ResourceString class so that you can do something like:
private static readonly ResourceString res = "The value";
and then refer to that in the code. Behind the scene, the ResourceString class does the work. Here is an example of that:
namespace ResString
{
public interface IResourceResolver
{
string Resolve(string key, string defaultValue);
}
public class ResourceString
{
public ResourceString(string value)
{
this.defaultValue = value;
GetOwner();
}
public string Value
{
get
{
if (!resolved)
Resolve();
return value;
}
}
public override string ToString()
{
return Value;
}
public static implicit operator string(ResourceString rhs)
{
return rhs.Value;
}
public static implicit operator ResourceString(string rhs)
{
return new ResourceString(rhs);
}
protected virtual void Resolve()
{
if (Resolver != null)
{
if (key == null)
key = GetKey();
value = Resolver.Resolve(key, defaultValue);
}
else
{
value = defaultValue;
}
resolved = true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
protected virtual void GetOwner()
{
StackTrace trace = new StackTrace();
StackFrame frame = null;
int i = 1;
while (i < trace.FrameCount && (owner == null || typeof(ResourceString).IsAssignableFrom(owner)))
{
frame = trace.GetFrame(i);
MethodBase meth = frame.GetMethod();
owner = meth.DeclaringType;
i++;
}
}
protected virtual string GetKey()
{
string result = owner.FullName;
FieldInfo field = owner.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(f =>
typeof(ResourceString).IsAssignableFrom(f.FieldType) && f.GetValue(null) == this
).FirstOrDefault();
if (field != null)
result += "." + field.Name;
return result;
}
public static IResourceResolver Resolver { get; set; }
private string defaultValue;
private string value;
private bool resolved;
private string key;
private Type owner;
}
}
And an example program:
namespace ResString
{
class Program
{
/// <summary>
/// Description for the first resource.
/// </summary>
private static readonly ResourceString firstRes = "First";
/// <summary>
/// Description for the second resource.
/// </summary>
private static readonly ResourceString secondRes = "Second";
/// <summary>
/// Description for the format string.
/// </summary>
private static readonly ResourceString format = "{0} {1}";
static void Main(string[] args)
{
ResourceString.Resolver = new French();
Console.WriteLine(String.Format(format, firstRes, secondRes));
}
private class French : IResourceResolver
{
public string Resolve(string key, string defaultValue)
{
switch (key)
{
case "ResString.Program.firstRes":
return "Premier";
case "ResString.Program.secondRes":
return "Deuxième";
case "ResString.Program.format":
return "{1} {0}";
}
return defaultValue;
}
}
}
}
If you run that, it will output:
Deuxième Premier
Comment out the Resolver assignment and you will get:
First Second
Any where you would use a string in the UI, use a declared ResourceString instead.
Changing the resolver after the string values have been resolved will not alter their value as the values are retrieved only once. You will of course need to write a real resolver that pulls from a database.
What you will then need is a utility program to run through the compiled classes and pull out the ResourceString declarations and put the key and default values into a database or text file so they can be translated. This should also go through the generated help XML files for each assembly and pull the comment for the ResourceString declarations so the translator has some context to work with. The key declarations will also provide context as you can easily group resources by UI class.
Add this to a build script the make sure it is updated regularly.
You can use the same approach with images and the like.
How can we call a function that is defined abstract in a generic base class.
I have a generic
class Class1<T> where T : class, new()
and multiple classes which derive from it like
Class2: Class1<Class2>
Class3: Class1<Class3>
The generic class has 3 functions
1-> accept a dynamic object and puts all the values to corresponding properties in the object of derive
2-> accepts the ID, looks for the corresponding row in database pass the dynamic object to func1 and return the result
3-> a listall function which returns all rows in table
Here is the generic code
public abstract partial class Class1<T> where T : class, new()
{
public static EntityLayout EntityLayout { get; protected set; }
[TypeAttributes(TypeAttributes.Options.IsPrimary, TypeAttributes.Options.IsAutoIncrement)]
/// <summary> Automatically Incremented 64 bit Integer Primary Key
/// represents the Unique ID of each row in Table </summary>
public long ID { get; set; }
/// <summary> Converts the row returned from Database to Object </summary>
/// <param name="row"></param>
/// <returns></returns>
public abstract T GetDetails(dynamic row);
public static T GetDetails(long ID)
{
var row = Shared.SessionWrapper.Current.globaldbcon.QuerySingle("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "] WHERE ID=#0", ID);
if (row != null) return GetDetails(row);
return new T();
}
public static List<T> ListAll()
{
List<T> result = new List<T>();
foreach (var row in Shared.SessionWrapper.Current.globaldbcon.Query("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "]")) result.Add(GetDetails(row));
return result;
}
}
An example class Implementation
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Arinsys.Database;
namespace WebApplication1.Models
{
[EntityAttributes(EntityAttributes.Options.TestingEnabled)]
public class Class3 : Class1<Class3>
{
static Class3()
{
EntityLayout.DisplayName = "Users";
}
/// <summary> User ID of the User </summary>
public long UID { get; set; }
/// <summary> User ID of the User if defined in Universal Data Store </summary>
public long UDSID { get; set; }
/// <summary> Login ID of User </summary>
public string LoginID { get; set; }
/// <summary> Registered email of the user. If not set will be set same as LoginID </summary>
public string Registeredemail { get; set; }
[TypeAttributes(TypeAttributes.Options.IsPassword)]
/// <summary> Password of user </summary>
public string Password { get; set; }
/// <summary> A Unique Security Stamp used for activation/deactivation of account or similar intense tasks </summary>
public string SecurityStamp { get; set; }
/// <summary> Timezone ID of the Default Timezone of User </summary>
public string DefaultTimezone { get; set; }
/// <summary> Current Status of User </summary>
public string CurrentStatus { get; set; }
/// <summary> Discriminator which defines the type of user in multi-user heirarchy scenario </summary>
public string UserType { get; set; }
/// <summary> Number of failed login attempts in total or same session depending upon configuration. Resets after Successful Login </summary>
public short FailedAttempts { get; set; }
/// <summary> Date Time of Last Failed Login Attempt in UTC </summary>
public DateTime LastFailedAttempt { get; set; }
/// <summary> Date Time of Last Successful Login in UTC </summary>
public DateTime LastLogin { get; set; }
/// <summary> Creation Date of User Account in UTC </summary>
public DateTime CreationDate { get; set; }
public override Class3 GetDetails(dynamic row)
{
Class3 result = new Class3();
if (row != null)
{
result.ID = Convert.ToInt64(row.ID);
result.UID = Convert.ToInt64(row.UID);
result.UDSID = Convert.ToInt64(row.UDSID);
result.UserType = row.UserType;
result.LoginID = row.LoginID;
result.Password = row.Password;
result.Registeredemail = row.Registeredemail;
result.SecurityStamp = row.SecurityStamp;
result.DefaultTimezone = row.DefaultTimezone;
result.CurrentStatus = row.CurrentStatus;
result.FailedAttempts = Convert.ToInt16(row.FailedAttempts);
result.LastFailedAttempt = Convert.ToDateTime(row.LastFailedAttempt);
result.LastLogin = Convert.ToDateTime(row.LastLogin);
result.CreationDate = Convert.ToDateTime(row.CreationDate);
}
return result;
}
}
}
Its been two weeks searching for the answer everywhere before posting, but couldn't find the solution.
All i want is that ListAll function should call 1st function. Since it's defined abstract i am sure the deriving class has to have an implementation (even though it might be just throw NotImplementException, but implementation is guaranteed)
I first defined the implementation of 1st function in generic class itself through reflection. Though that works, but its very slow, did performance bench-marking by starting/stopping a Stopwatch at start/end of controller action and it took approx 35 seconds for just 100 rows, so it's surely not something for production use.
Points to note
Static cannot be defined abstract
Cannot access instance member from static context
Cant use reflection because of performance issues
Possible Solutions i guess are closest ( but i am unable to understand how to use them in my case)
convert all methods to instance methods and use singleton
using interfaces
define a static method in derived class and assume it will be there in all classes, if i go this way then how to access static method on T in that case
What i want to achieve is that ListAll function should call 1st function accepting a dynamic object.
Some questions which come very close are these, but none of them solves my query.
Stack Overflow Q1 Stack Overflow Q2 Stack Overflow Q3
Looks like the design should be like this
public abstract partial class Class1<T> where T : Class1<T>, new()
{
protected abstract void Load(dynamic row);
private static T GetItem(dynamic row)
{
var item = new T();
if (row != null)
item.Load(row);
return item;
}
public static T GetDetails(long ID)
{
var row = Shared.SessionWrapper.Current.globaldbcon.QuerySingle("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "] WHERE ID=#0", ID);
return GetItem(row);
}
public static List<T> ListAll()
{
List<T> result = new List<T>();
foreach (var row in Shared.SessionWrapper.Current.globaldbcon.Query("SELECT * FROM ["
+ EntityLayout.ContainerName + "].["
+ EntityLayout.TableName + "]")) result.Add(GetItem(row));
return result;
}
}
and the sample implementation
public class Class3 : Class1<Class3> {
{
// ...
protected override void Load(dynamic row)
{
// No need to check for null, it is enforced by the base class
ID = Convert.ToInt64(row.ID);
UID = Convert.ToInt64(row.UID);
// ...
}
}
Basically you explore the Curiously recurring template pattern supported by .NET generic class constraints (T : Class1<T>) to ensure the derived class contains the abstract Load method, while the new T() part is enforced by the new() constraint.
I have the following issue related to reflection , I have a method which looks like this :
[TestMethod()]
public void steamAccess()
{
testRead = new TestRead();
SteamMap a = new SteamMap();
// Preparing the parameters of the CSV actions
a.writeMessageParams.UIItemEditText = TestContext.DataRow["SearchQuery"].ToString();
//Read and Execute the TestMethod
testRead.Read(a, TestContext);
}
This is a CodedUITest, SteamMap is a class (uiTest map).
WriteMessageParams is a class, actually the real method is WriteMessage but this class allows me to override the string that gets used into my tests by the WriteMessage method, and I plan to make this part of the code more dynamically in the Read method. :
a.writeMessageParams.UIItemEditText = TestContext.DataRow["SearchQuery"].ToString();
My problem happens in testRead.Read context as follows :
When this method is running I have access to all actions from the respective instance ( a in my case ) and if they are supposed to have to use a a.writeMessageParams.UIItemEditText context I know it, how I get the info isn't the problem, the problem is how to make the previously mentioned code to run dynamically as I have tried :
/* I've done this because I know that each method that is supposed to end up with Params, for example a method called WriteMessage, it's class is called WriteMessageParams*/
public void Read(object obj, TestContext testContext)
{
//simplified code
//trying to access/get to the current instance's WriteMessageParam class
Object testObj = obj.GetType().GetMember(subMethod.Code + "Param");
//null
MessageBox.Show(testObj.GetType().ToString());
// trying to access the UIItemEditText field ( which is declared as public) and modify it accordingly
FieldInfo subMethodField = testObj.GetType().GetField("UIItemEditText");
subMethodField.SetValue(testObj,testContext.DataRow[subMethod.CsvColumn].ToString());
}
I've had a read over this article and tried few things
https://msdn.microsoft.com/en-us/library/6z33zd7h%28v=vs.110%29.aspx
My problem is that I have the object of an instance and I try to access this object's class and modify that class's field .
I'd appreciate any help,
Thanks
Edit 1:
This is how the class I'm trying to access looks like :
public partial class SteamMap
{ //simplified to what classes/methods interest me
public virtual writeMessageParams writeMessageParams
{
get
{
if ((this.mwriteMessageParams == null))
{
this.mwriteMessageParams = new writeMessageParams();
}
return this.mwriteMessageParams;
}
}
public class writeMessageParams
{
#region Fields
/// <summary>
/// Type 'test' in text box
/// </summary>
public string UIItemEditText = "test";
#endregion
}
}
Edit 2 - I've tried by using GetNestedType, still no success....
Object testObj = obj.GetType().GetNestedType("writeMessageParams",BindingFlags.Public);
MessageBox.Show(testObj.GetType().ToString());
If I understand you, you have a class like
public partial class SteamMap
{
private writeMessageParams mwriteMessageParams ;
public virtual writeMessageParams writeMessageParams1
{
get
{
if ((this.mwriteMessageParams == null))
{
this.mwriteMessageParams = new writeMessageParams();
}
return this.mwriteMessageParams;
}
}
public class writeMessageParams
{
public string UIItemEditText = "test";
}
}
(your code doesn't compile because you have writeMessageParams both as the class and the property, so I have changed the property to writeMessageParams1)
And you want to change UIItemEditText, which you can do like
public void UpdateUI(object obj, string newValue)
{
var property = obj.GetType().GetProperty("writeMessageParams1");
var writeMessageParams1 = property.GetValue(obj);
var uiFld = wp.GetType().GetField("UIItemEditText");
uiFld.SetValue(writeMessageParams1, newValue);
}
which can be called like
SteamMap sm = new SteamMap();
Write(sm, "Hello");
The key is to use .GetProperty for the property and .GetField for the field.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to figure out how to set a property as a primary key. What I mean is, I have a POCO object I'm trying to define a key for like this:
public class POCO
{
[PrimaryKey]
int Id;
string Name;
int Age;
}
Then I'm trying to access it like this:
public static object ReturnKeyValue(this POCO poco)
{
return poco.[PrimaryKey]; //should return Id
}
What am I doing wrong here?
I had something similar, which to which I found a solution yesterday, so I'm happy to share it.
Something you need to know is that what you're trying to do will never work when you have a composite key, which means, having a POCO object that has a primary key that conists out of more than 1 single element.
Let's say that I have the following class (POCO):
public class Person : EntityBase<int>
{
#region Properties
/// <summary>
/// Gets or sets the id of the entity.
/// </summary>
[Key]
public TKey Id { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the firstname.
/// </summary>
public string FirstName { get; set; }
/// <summary>
/// Gets or sets the <see cref="Manager"/>.
/// </summary>
public Manager Manager { get; set; }
#endregion
}
I'm using Entity Framework here, therefore the attribute that defines the Primary Key is called Key and not PrimaryKey as in your example.
Now, I do have class that acts a repository. That class hold all the objects of Person in an object, in my Test-scenario, it's holding those objects in an HashSet:
private readonly HashSet<TEntity> _entitiesCollection = new HashSet<TEntity>();
Where TEntity is offcourse the Person entity.
Further, this class does have a List<PropertyInfo>' object, named_keyProperties`, that will hold all the keys for the object.
Now, I do have a method that will find all the properties that act as a key for the given object:
private void GetKeyProperties()
{
_keyProperties = new List<PropertyInfo>();
var properties = typeof(TEntity).GetProperties();
foreach (var property in from property in properties from attribute in property.GetCustomAttributes(true).OfType<KeyAttribute>() select property)
{ _keyProperties.Add(property); }
}
No, you can for example select all your that matches a given value for the primary keys. This can be achieved with a method like:
protected virtual TEntity Find(params object[] keyValues)
{
if (keyValues.Length != _keyProperties.Count) throw new ArgumentException("Incorrect number of keys passed to find method");
var keyQuery = this.AsQueryable();
keyQuery = keyValues.Select((t, i) => i).Aggregate(keyQuery, (current, x) => current.Where(entity => _keyProperties[x].GetValue(entity, null).Equals(keyValues[x])));
return keyQuery.SingleOrDefault();
}
Or, for example, if you want to perform an update of an entity, you can execute the following:
public void Update(TEntity entity)
{
// First the original entity is retrieve by searching the key, this item is then removed from the collection
// Then a new item is being added to the collection.
var original = Find(_keyProperties.Select(e => e.GetValue(entity)).ToArray());
Detach(original);
_entitiesCollection.Add(entity);
}
What this does is searching the original entity based on the primary key, remove that entity and then add the updated one again.
So, I hope this helps.
Can the POCO class's PrimaryKey property be made public, with a getter and setter, like this?
public class POCO
{
[PrimaryKey]
public int Id { get; set; }
string Name;
int Age;
}
If so, then the following extension method should return the PrimaryKey field's value for any given POCO instance.
public static object ReturnKeyValue(this POCO poco)
{
return (from p in poco.GetType().GetProperties()
let attr = p.GetCustomAttributes(typeof(PrimaryKeyAttribute), true)
where attr.Length == 1
select p).First().GetValue(poco, null);
}
I have the following class:
public class OrgAlertList
{
public string CustMailName { get; set; }
/// <summary>
/// Gets all the alerts that apply to this customer.
/// </summary>
public virtual IEnumerable<OrgAlertSummary> Alerts { get; set; }
}
That contains a property (named Alerts) that is an IEnumerable of my second class:
public class OrgAlertSummary
{
/// <summary>
/// Message detailing the alert for the user.
/// </summary>
public string Message { get; set; }
/// <summary>
/// Message detailing how to fix alert.
/// </summary>
public string ActionMessage { get; set; }
}
The Alerts property in the OrgAlertList can contain zero to many OrgAlertSummary items.
I need to write a Lambda expression, or use a LINQ query, to flatten the classes into a new type that has the CustMailName, Message, and ActionMessage in it for each OrgAlertList item where the Alerts property contains at least one OrgAlertSummary item. Can anyone help with this?
Try this: (untested)
var q = from orgAlert in myOrgAlertList
from orgAlertSummary in orgAlert.Alerts
select new { orgAlert.CustomMailName,
orgAlertSummary.Message,
orgAlertSummary.ActionMessage};
Assuming myOrgAlertList is some sort of IEnumerable<OrgAlertList>
This query will create an anonymous type with fields named CustomMailName, Message, and ActionMessage. If you intend to export this resulting list to other modules, it's recommended to define your own class and create it in the select instead of using an anonymous type.