Query Object Structure using string input - c#

I'm trying to find a clean way to allow input of a string that can then query an object structure. I think a dynamic linq query is what I want but I can't figure out how to implement this.
The user would input a string like
relationship.IsHappy = true
or
relationship.Type = "Uncle"
or
relationship.Type = "Uncle" && relationship.IsHappy = true
The last two lines in main() are what I'm trying to find a solution for:
string zQuery = args[0];
me.Realtionships.Where(zQuery);
Complete code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic;
namespace LinqTest1
{
class Program
{
static void Main(string[] args)
{
person me = new person();
me.FirstName = "Andy";
me.Realtionships = new List<relationship>();
person aunt = new person();
aunt.FirstName = "Lucy";
relationship rAunt = new relationship();
rAunt.IsHappy = true;
rAunt.Type = "Aunt";
rAunt.Person = aunt;
me.Realtionships.Add(rAunt);
person uncle = new person();
uncle.FirstName = "Bob";
relationship rUncle = new relationship();
rUncle.IsHappy = false;
rUncle.Type = "Aunt";
rUncle.Person = uncle;
me.Realtionships.Add(rUncle);
string zQuery = args[0];
me.Realtionships.Where(zQuery);
}
}
public class person
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
private List<relationship> _realtionships;
public List<relationship> Realtionships
{
get { return _realtionships; }
set { _realtionships = value; }
}
}
public class relationship
{
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
private bool _isHappy;
public bool IsHappy
{
get { return _isHappy; }
set { _isHappy = value; }
}
private person _person;
public person Person
{
get { return _person; }
set { _person = value; }
}
}
}

you can use :
Dynamic expression trees Inbuilt libraries
or
Dynamic Linq queries A microsoft library with source and examples you can download.
Constructing an expression tree is a little more involved but ultimately more powerful. And you will eat and sleep Lambda when your have finished.
The Dynamic Linq library allows you to pass strings to a tool that parses the strings and creates Lambda expressions. This is easier to use.

There is a library called dynamic Linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx that allows you to use Strings instead of expression trees for Linq queries.

We did this with an expression tree serializer/deserializer. I believe in your case you just need to deserialize the passed in string, we used this http://expressiontree.codeplex.com/

Thanks. The piece I was missing was AsQueryable(). See solution below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Dynamic;
namespace LinqTest1
{
class Program
{
static void Main(string[] args)
{
person me = new person();
me.FirstName = "Andy";
me.Realtionships = new List<relationship>();
person aunt = new person();
aunt.FirstName = "Lucy";
relationship rAunt = new relationship();
rAunt.IsHappy = true;
rAunt.Type = "Aunt";
rAunt.Person = aunt;
me.Realtionships.Add(rAunt);
person uncle = new person();
uncle.FirstName = "Bob";
relationship rUncle = new relationship();
rUncle.IsHappy = false;
rUncle.Type = "Uncle";
rUncle.Person = uncle;
me.Realtionships.Add(rUncle);
//string zQuery = args[0];
var res = me.Realtionships.AsQueryable().Where("Type == \"Uncle\"");
foreach (relationship item in res)
{
Console.WriteLine(item.Person.FirstName);
}
Console.ReadLine();
}
}
public class person
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
private List<relationship> _realtionships;
public List<relationship> Realtionships
{
get { return _realtionships; }
set { _realtionships = value; }
}
}
public class relationship : IEnumerable<relationship>
{
private string _type;
public string Type
{
get { return _type; }
set { _type = value; }
}
private bool _isHappy;
public bool IsHappy
{
get { return _isHappy; }
set { _isHappy = value; }
}
private person _person;
public person Person
{
get { return _person; }
set { _person = value; }
}
public IEnumerator<relationship> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}

Related

Add objects of a class and store in a static field of another class and access them through properties of the second class

I want to store objects of a non-static class in static fields of another non-static class and access them through the properties of the second class. Please, help me.
class Student
{
private string fullname;
private string course;
private string subject;
public Student(string fullname, string course)
{
this.fullname = fullname;
this.course = course;
}
public Student(string fullname, string course, string subject)
{
this.fullname = fullname;
this.course = course;
this.subject = subject;
}
public string FullName { get { return fullname; } set { fullname = value; }}
public string Course { get { return course; } set { course = value; }}
public string Subject { get { return subject; } set { subject = value;}}
}
class StudentData
{
private static Student bscStudent;
private static Student mscStudent;
public StudentData()
{
}
private static void GetStudentData()
{
Student student = new Student(" Isoboye Vincent", "IT");
Student student2 = new Student(" Doris Atuzie", "IT", "C#");
bscStudent= student;
mscStudent= student2;
}
public static Student BscStudent { get { return bscStudent; } set { bscStudent = value; } }
public static Student MscStudent { get { return mscStudent; } set { mscStudent = value; } }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("List of students");
Console.WriteLine(StudentData.BscStudent);
Console.WriteLine(StudentData.MscStudent);
Console.ReadKey();
}
}
// Output:
//List of students
-
Now I understand the problem, so I propose this solution:
private static Student _BscStudent = null;
public static Student BscStudent {
get {
if (_BscStudent == null) {
_BscStudent = new Student(" Isoboye Vincent", "IT");
}
return _BscStudent;
}
set { _BscStudent = value; }
}
private static Student _MscStudent = null;
public static Student MscStudent {
get {
if (_MscStudent == null) {
_MscStudent = new Student(" Doris Atuzie", "IT", "C#");
}
return _MscStudent;
}
set {
_MscStudent = value;
}
}
I did not work with C# for a very long time, so I might not remember an easier way. Anyway, start with this solution and maybe later if you find out a better way, then refactor this code.

Convert two classes in VB.net to C# but get object reference error

I have converted the following two classes to c# from vb.net, but get a reference error. Can someone please help or explain why it does not work in c# but does in vb.net?
Member class:
public class Member
{
#region "Fields"
private string fPiecemark;
private string fMemberType;
private string fSize;
private string fTotalWeight;
private int fSheetKey;
private string fDescription;
private string fStructType;
#endregion
private string fMemberSheetIndex;
#region "Constructors"
//Default class Constructor
public Member()
{
fPiecemark = string.Empty;
fMemberType = string.Empty;
fSize = string.Empty;
fTotalWeight = string.Empty;
fSheetKey = 0;
fStructType = string.Empty;
}
public Member(string Piecemark, string MemberType, string Description, string Size, string TotalWeight, string StructType, string MemberSheetIndex, int SheetID)
{
this.Piecemark = Piecemark;
this.MemberType = MemberType;
this.Description = Description;
this.Size = Size;
this.TotalWeight = TotalWeight;
this.StructType = StructType;
this.MemberSheetIndex = MemberSheetIndex;
this.SheetKey = SheetID;
if (!MbrSheet.mSheet.ContainsKey(SheetID))
{
MbrSheet.mSheet.Add(SheetID, new MbrSheet(SheetID));
}
MbrSheet.mSheets[SheetID].Members.Add(this);
}
#endregion
#region "Properties"
public string Piecemark
{
get { return fPiecemark; }
set { fPiecemark = value; }
}
public string MemberType
{
get { return fMemberType; }
set { fMemberType = value; }
}
public string TotalWeight
{
get { return fTotalWeight; }
set { fTotalWeight = value; }
}
public string Size
{
get { return fSize; }
set { fSize = value; }
}
public int SheetKey
{
get { return fSheetKey; }
set { fSheetKey = value; }
}
public string Description
{
get { return fDescription; }
set { fDescription = value; }
}
public string StructType
{
get { return fStructType; }
set { fStructType = value; }
}
public string MemberSheetIndex
{
get { return fMemberSheetIndex; }
set { fMemberSheetIndex = value; }
}
#endregion
}
MbrSheet class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
public class MbrSheet
{
public static Dictionary<int, MbrSheet> mSheets = new Dictionary<int, MbrSheet>();
public int mSheet { get; set; }
public List<Member> Members { get; set; }
public MbrSheet(int MbrSheet)
{
Members = new List<Member>();
this.mSheet = MbrSheet;
}
public static decimal WeightByType(string MemberType)
{
var subset = mSheets.Where(kvp => kvp.Value.Members.Where(m => m.MemberType == MemberType).Count() > 0);
decimal wbt = 0;
wbt += mSheets
.Where(kvp => kvp.Value.Members.Where(m => m.MemberType == MemberType).Count() > 0)
.Sum(kvp => kvp.Value.Members.Sum(m => Convert.ToDecimal(m.TotalWeight, CultureInfo.InvariantCulture)));
return wbt;
}
}
I get error but don't know why
An object reference is required for the non-static field, method, or property for MbrSheet.mSheet, but both worked in VB.net
if (!MbrSheet.mSheet.ContainsKey(SheetID)) // Error on !MbrSheet.mSheet
{
MbrSheet.mSheet.Add(SheetID, new MbrSheet(SheetID)); // Error on MbrSheet.mSheet
}
I think you should use this:
if (!MbrSheet.mSheets.ContainsKey(SheetID))
{
MbrSheet.mSheets.Add(SheetID, new MbrSheet(SheetID));
}
Pay attention to mSheets you are using mSheet.
You can also use tools to convert codes:
http://www.developerfusion.com/tools/convert/csharp-to-vb/
http://codeconverter.sharpdevelop.net/SnippetConverter.aspx

Error: "No row with the given identifier exists[ITELnetERP.Model.Continent#AF ]" in C# with Castle

I am starting a new project using C# + Castle ActiveRecord with PostgreSQL. I have this two classes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.ActiveRecord;
namespace ITELnetERP.Model
{
[ActiveRecord("countries", Table = "countries")]
public class Country : ActiveRecordBase<Country>
{
private string _code;
private string _iso3;
private string _number;
private string _name;
private Continent _continent;
private string _calling_code;
private DateTime _created_at;
private DateTime _updated_at;
[PrimaryKey(PrimaryKeyType.Assigned, Column = "code")]
public string Code
{
get { return _code; }
set { _code = value; }
}
[Property("iso3")]
public string ISO3
{
get { return _iso3; }
set { _iso3 = value; }
}
[Property("number")]
public string Number
{
get { return _number; }
set { _number = value; }
}
[Property("name")]
public string Name
{
get { return _name; }
set { _name = value; }
}
[Property("calling_code")]
public string CallingCode
{
get { return _calling_code; }
set { _calling_code = value; }
}
[BelongsTo("continent_code")]
public Continent Continent
{
get { return _continent; }
set { _continent = value; }
}
[Property("created_at")]
public DateTime CreatedAt
{
get { return _created_at; }
set { _created_at = value; }
}
[Property("updated_at")]
public DateTime UpdatedAt
{
get { return _updated_at; }
set { _updated_at = value; }
}
}
}
and:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.ActiveRecord;
using System.Collections;
namespace ITELnetERP.Model
{
[ActiveRecord("continents")]
public class Continent : ActiveRecordBase<Continent>
{
private string _code;
private string _name;
private DateTime _created_at;
private DateTime _updated_at;
private IList _countries = new ArrayList();
[PrimaryKey(PrimaryKeyType.Assigned, Column = "code")]
public string Code
{
get { return _code; }
set { _code = value; }
}
[Property("name")]
public string Name
{
get { return _name; }
set { _name = value; }
}
[HasMany(typeof(Country), Table = "countries", ColumnKey = "continent_code")]
public IList Countries
{
get { return _countries; }
set { _countries = value; }
}
[Property("created_at")]
public DateTime CreatedAt
{
get { return _created_at; }
set { _created_at = value; }
}
[Property("updated_at")]
public DateTime UpdatedAt
{
get { return _updated_at; }
set { _updated_at = value; }
}
}
}
on my startup file I have this (Note I am using PostgreSQL as DBMS):
static void Main()
{
// Read Configuration for Database
IDictionary<string, string> properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.NpgsqlDriver");
properties.Add("dialect", "NHibernate.Dialect.PostgreSQLDialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("connection.connection_string", "Server=localhost;Port=5433;Database=ITELnet_ERP;Uid=itelnet_erp;Pwd=itelnet");
properties.Add("proxyfactory.factory_class", "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");
InPlaceConfigurationSource source = new InPlaceConfigurationSource();
source.Add(typeof(ActiveRecordBase), properties);
// Initialize Database
ActiveRecordStarter.Initialize(source, GetActiveRecordTypes());
// Start the Application
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
When I try to select all "Countries" from the database using following statement:
var countries = Country.FindAll();
foreach (Country country in countries)
{
MessageBox.Show("Country Name: " + country.Name);
}
I get this error:
An unhandled exception of type 'Castle.ActiveRecord.Framework.ActiveRecordException' occurred in Castle.ActiveRecord.dll
Additional information: Could not perform FindAll for Country
Image for more details:
What is wrong with my code?
How can I solve that?
Thanks for your attention
Regards
PS

How can I pass a value to a child/list object?

I am trying to pass a value to a list of the same object by using the following code.
Using the following code I get a "A field initializer cannot reference the non-static field, method, or property" error.
If I change the Surname property to fix this I get 2 more errors.
The idea is to create an object of a person and pass their surname on to their children in the list.
The code:
public class Person
{
public Person()
{
}
private string name = "";
public string Name
{
get { return name; }
set { if (name != value) name = value; }
}
private string surname = "";
public string Surname
{
get { return surname; }
set { if (surname != value) surname = value; }
}
private Children sourceList = new Children(Surname);
public Children SourceList
{
get { return sourceList; }
set { if (sourceList != value) sourceList = value; }
}
}
[TypeConverter(typeof(TypeConverter))]
public class Children : List<Person>
{
public Children(string surname)
{
this.ForEach(person => { person.Surname = surname; });
}
}
Please help?
Thanks in advance.
this line is causing you the issue: private Children sourceList = new Children(Surname);
The reason is that field initializers are limited in what they can access, the c# spec states that they can't reference the instance that's being created, so you can' access Surname in a field declaration.
You can set your properties in the constructor
Remove the constructor from Children class, and put the ´foreach statement´ in the set of SourceList, and create a new sourcelist only in the getter if is not inicialized.
Just like this:
public class Person
{
public Person()
{
}
private string name = "";
public string Name
{
get { return name; }
set { if (name != value) name = value; }
}
private string surname = "";
public string Surname
{
get { return surname; }
set { if (surname != value) surname = value; }
}
private Children sourceList;
public Children SourceList
{
get {
if(sourceList == null)
sourceList = new Children();
return sourceList;
}
set { if (sourceList != value)
sourceList = value.ForEach(person => { person.Surname = surname; });
}
}
}
[TypeConverter(typeof(TypeConverter))]
public class Children : List<Person>
{
}

How do I convert BindingSource.DataSource to my custom object?

I have a custom dataset style class defined as:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace LibrarySort.Data
{
public class LibraryData
{
private AlbumList albums;
public AlbumList Albums { get { return albums; } }
public LibraryData()
{
this.albums = new AlbumList();
this.albums.AllowEdit = true;
this.Albums.AllowNew = true;
this.Albums.AllowRemove = true;
}
public void FillAll()
{
this.Albums.Fill();
}
}
public class AlbumList : BindingList<Album>
{
public AlbumList()
{
}
public void Fill()
{
int id = 1;
Album album1 = new Album();
album1.Id = id++;
album1.Artist = "Classical Piano Artist";
album1.Download = true;
album1.Person = null;
album1.Price = (decimal?)3.49;
album1.Tags.Add("classical");
album1.Tags.Add("piano");
album1.Title = "Classical Piano";
Album album2 = new Album();
album2.Id = id++;
album2.Artist = "Thrash Metal Artist";
album2.Download = false;
album2.Person = null;
album2.Price = (decimal?)7.99;
album2.Tags.Add("thrash metal");
album2.Title = "Thrash Metal";
this.Items.Add(album1);
this.Items.Add(album2);
}
}
}
I also a have Form object that inside a TabControl has a DataGridView. In the designer, I created a BindingSource and used the Add Project Data Source to create a source from the top level LibraryData object. I then bind the DataGridView to the "Albums" data member, all in the designer, and the columns get populated in the designer as expected.
When running the code, the table isn't populated, which makes sense as the Fill() hasn't been run. So I create a Load event handler for the form as follows:
private void MainForm_Load(object sender, EventArgs e)
{
LibraryData data = (LibraryData)bindingSource.DataSource;
data.FillAll();
}
However on run I get the following in MainForm_Load():
System.InvalidCastException was unhandled
Message="Unable to cast object of type 'System.RuntimeType' to type 'LibrarySort.Data.LibraryData'
I've Googled extensively on this, and in StackOverflow but no luck. Am I missing something?
Update: DataSource is definitely non-null. Also interestingly, in the designer code I see this:
this.bindingSource.DataSource = typeof(LibrarySort.Data.LibraryData);
Update 2: Album class and parent Item:
namespace LibrarySort.Data
{
public class Album : Item
{
bool download = false;
public bool Download { get { return download; } set { download = value; } }
string artist = null;
public string Artist { get { return artist; } set { artist = value; } }
}
}
namespace LibrarySort.Data
{
public class Item
{
int id = -1;
public int Id { get { return id; } set { id = value; } }
// FK to Person that currently has possession of item
int? person = null;
public int? Person { get { return person; } set { person = value; } }
string title = null;
public string Title { get { return title; } set { title = value; } }
decimal? price = null;
public decimal? Price { get { return price; } set { price = value; } }
State state = State.Owned;
public State State { get { return state; } set { state = value; } }
List<string> tags = null;
public List<string> Tags
{
get
{
if (tags == null)
tags = new List<string>();
return tags;
}
// No set needed
}
}
}
I think the issue is that although you have a binding source on your form, you have not set the datasource of the binding source.
Assuming that bindingSource is the datasource you dropped on your form, then try the following in the MainForm_Load:
LibraryData data = new LibraryData();
data.FillAll();
bindingSource.DataSource = data;

Categories

Resources