I want to use an own function to work with different database tables. As I'm using SQLite, the tables are filled using custom classes.
I'm trying to fill them recursively so I've created this struct and array:
public class cCodesPair
{
public string cCodeKey { get; set; }
public Type CommonCodeClass { get; set; }
public cCodesPair(string key, Type o)
{
this.cCodeKey = key;
this.CommonCodeClass = o;
}
}
private cCodesPair[] codesPairs = new cCodesPair[]
{
new cCodesPair("DESC_UNITS", typeof(SQLEventUnits)),
new cCodesPair("DESC_DISCIPLINE", typeof(SQLDisciplines)),
new cCodesPair("DESC_COUNTRY", typeof(SQLCountries)),
new cCodesPair("DESC_VIDEOS", typeof(SQLVideos)),
new cCodesPair("DESC_ATHLETES", typeof(SQLAthletes))
};
The idea of creating this, was to loop through the array to create query the table and to fill a Dictionary for each.
The function that tries to do that is:
public void Load<T>(T t, SQLiteConnection conn) where T : Type
{
try
{
var query = conn.Table<T>;
//MORE CODE...
} catch (Exception ex)
{
Debug.WriteLine("Exception")
}
}
The function that loops through the array and calls the Load function is the following one:
private async Task fillDictionaries()
{
for (int i = 0; i < codesPairs.Length; i++)
{
MasterDescriptions m = new MasterDescriptions();
Type t = codesPairs[i].CommonCodeClass;
m.Load(t, conn);
}
}
But I get that the table queried has been one called Type.
I would like to get Tables SQLEventUnits, SQLDisciplines, etc dinamically.
Anyone knows how to?
Thanks in advance!
Do you know Microsoft Enterprise Library?
https://msdn.microsoft.com/en-us/library/ff648951.aspx
Does exactly what you want to implement.
Another reference:
http://www.codeproject.com/Tips/657233/Enterprise-Library-6-Sqlite-Logging-and-Exceptions
Related
class abc {
string value1 = "", value2 = "", ........... valueN = "";
#region Methods
public void method1(DataSet dataSet) {
populate valueS using populateValues() and use it for doing something
}
....
public void methodN(DataSet dataSet) {
populate valueS using populateValues() and use it for doing something else
}
#endregion
public void populateValues(DataSet dataSet) {
#region populate valueS so they can be used by methodS
if(dataSet.Tables.Contains("Table1") {
var dataRow1 = dataSet.Tables["Table1"].Select();
if(dataRow1.Length > 0) {
value1 = dataRow1[0]["value1"].ToString()
}
}
.....
if(dataSet.Tables.Contains("TableN") {
var dataRowN = dataSet.Tables["TableN"].Select();
if(dataRowN.Length > 0) {
valueN = dataRowN[0]["valueN"].ToString()
}
}
#endregion
}
}
The above snippet is an abstract skeleton of a large legacy project in which there are many methodS() like:
method1()
method2()
.....
methodN()
Almost all of these require almost all valueS:
value1
value2
...
valueN
which are populated using populateValues().
This is how abc is used in other places:
class xyz {
abc a = new abc();
public void doingSomething() {
//Get data from DB and populate to dataSet
a.method1();
a.method5();
....
}
public void doingSomethingElse() {
//Get data from DB and populate to dataSet
a.method1();
return;
}
}
doingSomething() is part of a web service project which is mostly called at the same time from few overlapping-lu running windows service projects.
I'm seeing a danger of possible overwriting of valueS by populateValues() when any of the methodS() are called in parallel.
The structure of dataSet is mostly unpredictable and hence I always need to check the Table1 existence.
The methods will mostly be called in parallel as they're part of a web services project.
How do I save myself from overwriting these large number of values without messing the code in C#?
In other words, how do we make sure that the valueS set after methodN() is not passed to methodN+1() when they're called simultaneously?
The most safe approach would be to copy pasted entire populateValues() body in each methodS() however, this will mess the project a lot.
Declare a class having all Values
Class resultVals
{
string value1 = "", value2 = "", ........... valueN = "";
}
Modify populateValues to return new class resultVals.
public resultVals populateValues(DataSet dataSet) {
resultVals valueS =new resultVals() ;
#region populate valueS so they can be used by methodS
if(dataSet.Tables.Contains("Table1") {
var dataRow1 = dataSet.Tables["Table1"].Select();
if(dataRow1.Length > 0) {
valueS.value1 = dataRow1[0]["value1"].ToString()
}
}
.....
if(dataSet.Tables.Contains("TableN") {
var dataRowN = dataSet.Tables["TableN"].Select();
if(dataRowN.Length > 0) {
valueS.valueN = dataRowN[0]["valueN"].ToString()
}
}
#endregion
}
return resultVals ;
}
Use the returned value (resultVals) in all methods.
public void method1(DataSet dataSet) {
resultVals valueS = populateValues()
and use it for doing something
}
You need to synchronize populateValues
lock(new object())
{
var result = populateValues();
}
However, lock is the simplest one. There are others. ex, you can use Monitor class as well.
Remove all the fields from the abc class.
Remove populate values method.
Create extension method to get value by a number.
Use the extension in place of the valueN field (easily regexp replaced in the code file).
public static string GetValue(this DataSet dataSet, int n)
{
if (dataSet.Tables.Contains("Table" + n)
{
var dataRow = dataSet.Tables["Table" + n].Select();
if (dataRow.Length > 0)
{
return = dataRow[0]["value" + n].ToString()
}
}
return string.Empty;
}
public void method1(DataSet dataSet)
{
var value1 = dataSet.GetValue(1);
}
Better yet, combine this with the Anil's answer and use a struct
public struct Values
{
public string value1;
...
public string valueN;
public static Values Init(DataSet dataSet)
{
// populate values logic here (use the extension from above)
value1 = dataSet.GetValue(1);
...
valueN = dataSet.GetValue(N);
}
}
And then call the methods.
var dataSet = new DataSet();
var values = Values.Init(dataSet);
a.method1(values);
a.method5(values);
public void method1(Values values)
{
// use values.value1 instead of value1 here
}
Dearest fellow programmers,
I seem to lack some understanding as of how the referencing works in C#.
The case:
I tried to implement some sort of Memento proxy which would wrap an interface and store every parameter that we're provided to the method calls and store these into a list.
Whenever necessary we could call the RestoreState and the objects would "reset" to the original state.
The code:
Consumer and model object
class Program
{
static void Main(string[] args)
{
IMemento memento = new Memento();
PrestationInfo prestationInfo2 = new PrestationInfo { Advance = 2 };
memento.Add(prestationInfo2);
Console.WriteLine(prestationInfo2.Advance); //Expect 2
prestationInfo2.Advance = 1;
Console.WriteLine(prestationInfo2.Advance); //Expect 1
memento.RestoreState();
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Console.ReadKey();
}
}
[Serializable]
public class PrestationInfo
{
public int Advance { get; set; }
}
Memento
public interface IMemento
{
void Add(object pItem);
void RestoreState();
}
public class Memento : IMemento
{
public Memento()
{
MementoList = new Dictionary<long, object>();
ReferenceList = new List<object>();
ObjectIDGenerator = new ObjectIDGenerator();
}
private ObjectIDGenerator ObjectIDGenerator { get; set; }
private Dictionary<long, object> MementoList { get; set; }
private List<object> ReferenceList { get; set; }
public void Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
}
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
private static TCopy DeepCopy<TCopy>(TCopy pObjectToCopy)
{
using (MemoryStream memoryStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(memoryStream, pObjectToCopy);
memoryStream.Position = 0;
return (TCopy)binaryFormatter.Deserialize(memoryStream);
}
}
}
Extra info
My guess is, I'm doing/understand something wrong regarding the List.
I also tried the Interlocked.Exchange, playing around with "ref"'s, using WeakReference's and storing the object into a CareTaker object (and storing that CareTaker into the List), implement some copy Property thing...
And ... I just can't see it.
My expected result would be the PrestationInfo.Advance property containing the value 2. But it keeps
Try this:
Change the Add method:
public long Add(object pItem)
{
bool firstTime;
long id = ObjectIDGenerator.GetId(pItem, out firstTime);
if (firstTime)
{
var mementoObject = DeepCopy(pItem);
MementoList.Add(id, mementoObject);
ReferenceList.Add(pItem);
}
return id; // i need my memento! LOL
}
You should also add this accessor method:
public object GetRestoredState(long id)
{
return MementoList[id]; // you should put some range check here
}
Now that you have your id, you can fetch the restored state this way:
memento.RestoreState();
prestationInfo2 = memento.GetRestoredState(savedId); // <-- you got this when you called the Add()...
Console.WriteLine(prestationInfo2.Advance); //Expect 2, but still 1
Follow ups: you can also make the IMemento into a IMemento<T>, and adjust your code accordingly
Memento.Add needs a ref parameter modifier to access the original reference type pointer.
https://msdn.microsoft.com/en-us/library/14akc2c7.aspx?f=255&MSPPError=-2147217396
It looks like the problem is in your understanding of references in .NET
public void RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
//reference = PropertyCopy<PrestationInfo>.CopyFrom(mementoObject as PrestationInfo); //Property copy
//Interlocked.Exchange(ref reference, mementoObject); //Also tried this
}
}
}
The RestoreState method above does not return anything, and you're strictly operating on references, not their internal state. Inside your method object reference is a local reference. It is not the same as the external prestationInfo2 and your method simply makes reference point (refer) to the previously saved copy of the state of presentationInfo2.
You could modify it something like this:
public object RestoreState()
{
for (int i = 0; i < ReferenceList.Count; i++)
{
object reference = ReferenceList[i];
bool firstTime;
long id = ObjectIDGenerator.GetId(reference, out firstTime);
if (MementoList.ContainsKey(id))
{
object mementoObject = MementoList[id];
reference = mementoObject;
return reference;
}
}
return null;
}
And then call it like this:
presentationInfo2 = memento.RestoreState();
If you want the memento to track objects and magically restore their state you will have to make the objects themselves aware of the memento which introduces coupling or use reflection to modify the tracked references internal state. Basically you don't deserialize the persisted state into a new object but use reflection to overwrite the previously stored internal state into the tracked object reference.
Be careful though to store references using WeakReference otherwise you will find yourself with a nice case of memory leak.
I have four collections of objects:
public static ConcurrentBag<string> ProductCodes;
public static ConcurrentDictionary<string, Product> ProductDictionary;
public static ConcurrentBag<IIMIM00> iimiml; // 37782 items
public static ConcurrentBag<IIMAR00> iimarl; // 73516 items
public static ConcurrentBag<PRODUCTINF> additionall; // 6238 items
public static ConcurrentBag<PF_COSSTO> ProductsAndCosts; // 862096 items
So first of all I get a unique list of product codes I want to create new 'Product' objects from:
Parallel.ForEach(ProductsAndCosts, i => ProductCodes.Add(i.improd));
ProductCodes = new ConcurrentBag<string>(ProductCodes.Distinct().ToList())
The product class:
public class Product
{
public IIMIM00 iimim { get; set; }
public List<IIMAR00> iimar { get; set; }
public PRODUCTINF productAdditional { get; set; }
}
My routine to sort and create a dictionary with product code and product object:
Parallel.ForEach(ProductCodes, SortandCreate);
public static void SortandCreate(string productCode)
{
var product = new Product {iimim = iimiml.Single(x => x.IMPROD.Equals(productCode))};
try
{
product.iimar = iimarl.Where(x => x.ARPROD.Equals(productCode)).ToList();
}
catch (Exception)
{
product.iimar = new List<IIMAR00>();
}
try
{
product.productAdditional = additionall.Single(x => x.PRODUCTCOD.Equals(productCode));
}
catch (Exception)
{
product.productAdditional = new PRODUCTINF();
}
ProductDictionary.TryAdd(productCode, product);
}
The try catches are there because the Product object wont always have an instance of IIMAR00 or PRODUCTINF.
The solution I have come up with is very slow takes over 2:30 on a i5. I'm not sure if there is a better way to get around this.
You should never use try-catch for program flow, because throwing an handling exceptions takes much time. In fact it's a covert if-else. Simply add a null check and you'll gain the time lost by exception handling:
product.iimar = iimarl.Where(x => x.ARPROD != null
&& x.ARPROD.Equals(productCode))
.ToList();
I have a class GetSearchFilters_Results which has two lists:
[DataContract]
public class GetSearchFilters_Results
{
public List<ElementList> ElementList{ get; set; }
public List<Managers> ManagerList { get; set; }
}
I have a file called Service.cs:
public GetSearchFilters_Results GetSearchFilters(string DomainID)
{
//Main List return List
//List<GetSearchFilters_Results> SearchFilterResults = new List<GetSearchFilters_Results>();
//Class
GetSearchFilters_Results GSF = new GetSearchFilters_Results();
string cs = ConfigurationManager.ConnectionStrings["TestDB"].ConnectionString;
try
{
using (SqlConnection con = new SqlConnection(cs))
{
con.Open();
SqlCommand cmd = new SqlCommand("spCPMapp_GetSearchFilters", con);
cmd.Parameters.AddWithValue("#Domain_Id", DomainID);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataAdapter sqlDa = new SqlDataAdapter(cmd);
DataSet Ds = new DataSet();
sqlDa.Fill(Ds);
DataTable DtWBS = new DataTable();
DataTable DTManager = new DataTable();
sqlDa.Fill(Ds);
DtWBS = Ds.Tables[0];
DTManager = Ds.Tables[1];
//Get WBS Elements List
if (DtWBS.Rows.Count > 0)
{
List<ElementList> ElementList= new List<ElementList>();
for (int i = 0; i < DtWBS.Rows.Count; i++)
{
ElementList wbs = new ElementList();
wbs.ProjectID = Convert.ToInt32(DtWBS.Rows[i]["Project_ID"].ToString());
wbs.WBSElementName = DtWBS.Rows[i]["WBSShort"].ToString();
WBSElementsList.Add(wbs);
//GSF.WBSElementsList.Add(wbs);
}
GSF.WBSElementsList = WBSElementsList;
//SearchFilterResults.Add(GSF);
}
//Get Managers List Start
if (DTManager.Rows.Count > 0)
{
List<Managers> ManagersList = new List<Managers>();
for (int i = 0; i < DTManager.Rows.Count; i++)
{
Managers Mgr = new Managers();
Mgr.TimeSheetID = Convert.ToInt32(DTManager.Rows[i]["Project_ID"].ToString());
Mgr.ManagerName = DTManager.Rows[i]["Manager"].ToString();
//GSF.ManagerList.Add(Mgr);
ManagersList.Add(Mgr);
}
GSF.ManagerList = ManagersList;
}
//Manager List End
}//Using End
//SearchFilterResults.Add(GSF);
}
catch (SqlException sqlEx)
{
sqlEx.ToString();
}
catch (FaultException ex)
{
ex.ToString();
}
catch (OverflowException e)
{
e.ToString();
}
return GSF.ManagerList; // I am getting error, how to add two lists into single objectGetSearchFilters_Results
}
And another class Elements:
[DataContract]
public class Elements
{
}
My questions are:
How can I add two separate lists into a single object?
I am getting an error if I add one list into the GetSearchFilter object that says:
Cannot implicitly convert type to System.Collection.Generic.List to System.Namespace.GetSearchFilterResult() method.
How do I fix this error?
Your problem is that you are returning a List and not a GetSearchFilter_Results.
If you intend to return a GetSearchFilter_Results object like the function header says, you can change your last line to:
return GSF;
Edit and side note:
You asked how to add two lists together. Assuming the lists are of the same object, you can use the AddRange() function like this:
List<string> stringListA = new List<string>();
List<string> stringListB = new List<string>();
stringListA.AddRange(stringListB); // stringListA now holds the elements from both A and B.
Another addition, hopefully I don't add too much
I've also noticed you don't differentiate how you catch each exception. I don't know what you need for your case, but you can eliminate several lines of code by simply saying:
catch(Exception e)
{
e.ToString();
}
Instead of multiple catch statements that all do the same thing.
You're posting an awful lot of code for this. Maybe try abstracting away a bit of your logic so it's cleaner and easier to read through?
Your problem is you're attempting to place a List<ManagerList> into a return of GetSearchFilters_Results. Though a List of ManagerList is a property of your GetSearchFilters_Results, they cannot be "implicitly converted" as the error states.
You would want to do something like this potentially:
[DataContract]
public class GetSearchFilters_Results
{
public List<ElementList> ElementList{ get; set; }
public List<Managers> ManagerList { get; set; }
public GetSearchFilters_Results
{
ElementList = new List<ElementList>();
ManagerList = new List<ManagerList>();
}
public GetSearchFilters_Results Execute()
{
this.ELementList = this.GetElementList();
this.ManagerList = this.GetManagerList();
return this;
}
public List<ElementList> GetElementList()
{
List<ElementList> list = new List<ElementList>();
// Get list information from db
return list;
}
public List<ManagerList> GetManagerList()
{
List<ManagerList> list = new List<ManagerList>();
// Get list information from db
return list;
}
}
You require the function
GetSearchFilters to return
GetSearchFilters_Results
but what you return really is
GSF.ManagerList
which is of type
List<Managers> ManagerList
That was your error. Anyway for the part 1 pf your question, you can create a class with two data members, each one is a list, then in the constructor or in a separated function, you pass two parameters each for list:
public Class TwoListsClass
{
List <type1> list1;
List <type2> list2;
public TwoListsClass (List <type1> list1, List <type2> list2)
{
this.list1 = list1;
this.list2 = list2;
}
}
then, when you finish the valuating of the two lists you can call the constructor or the function you wrote.
Wow, this is the older hard way to do things.... consider this: You already have two models.
public List<ElementList> ElementList{ get; set; }
public List<Managers> ManagerList { get; set; }
This tells me is could be generated from EF, which is good....
Now, there's a little known but very cool method in EF that looks like this:
public List<MyType> QueryThis(ViewModel vm)
{
using (var db = new MyEntities()){
var parms = GetParms(vm);
var query = Resources.QueryStrings.MyQuery;
var stuff = db.Database.SqlQuery<MyType>(query, parms);
return stuff.ToList();
}
Emphasis on the type being passed into the SQLQuery...
So all you really have to do is provide a new model that combines all the fields you want back and SQL will fill them in for you automatically. The class MyType will have all the fields from both models. SQL also knows how to populate base classes so you can inherit from one class and just enter in fields of the smaller class. No more parsing or even hitting the db more than once. Just tune up the query to get what you need in one shot.
All filtering from this point on can be done using LINQ... it's the new way to use the concepts of ADO.NET disconnected mode. When you dig into this a bit deeper you'll discover repositories, but that's for another day.
var filtered = MyTypeList.Where(p=>p.ManagerName == "SomeValue");
var filtered = MyTypeList.Where(p=>p.ElementType == "Somevalue");
I'm having some issues reading the properties of an item I have placed into an arraylist and I can't find the answer anywhere.
ArrayList itemsArrayList = new ArrayList();
itemsArrayList.Add(abyssalScepter);
itemsArrayList.Add(aegisOfTheLegion);
itemInBuildAbilityPower = itemsArrayList[0].abilityPower;
I need to be able to read the properties of the objects in the array so I can apply their values elsewhere but this gets me nowhere.
You need to cast object to the expected type (and hope it's really of this type).
itemInBuildAbilityPower = ((Item)itemsArrayList[0]).abilityPower;
The better option (if the infrastructure code is yours) to use generic container, e.g. List<T>.
List<Item> itemsArrayList = new List<Item>
itemsArrayList.Add(abyssalScepter);
itemsArrayList.Add(aegisOfTheLegion);
itemInBuildAbilityPower = itemsArrayList[0].abilityPower;
try
var itemInBuildAbilityPower = itemsArrayList[0].GetType().GetProperty ("abilityPower").GetGetMethod().Invoke (itemsArrayList[0], null);
Building on elder_george's answer, here is an example of what you could do if abyssalScepter and aegisOfTheLegion are not the exact same type:
using System.Collections.Generic;
class Power { }
interface IAbilityPower { Power abilityPower { get; set; } }
class Scepter : IAbilityPower { public Power abilityPower { get; set; } }
class Aegis : IAbilityPower { public Power abilityPower { get; set; } }
class Test
{
public static void Main()
{
var abyssalScepter = new Scepter();
var aegisOfTheLegion = new Aegis();
var itemsList = new List<IAbilityPower>();
itemsList.Add(abyssalScepter);
itemsList.Add(aegisOfTheLegion);
var power = itemsList[0].abilityPower;
}
}