I have a problem retrieving information from the database.
I have a function
public List<string> Selectquery(string sql)
{
return GetContext().ExecuteQuery<string>(sql).ToList();
}
where the variable sql:
var sql = "SELECT s.UserName AS username, st.Name AS status_name, c.FirstName FROM client c JOIN Suser s ON (c.UserID=s.ID) JOIN Status AS st ON (c.StatusID=st.ID) GROUP BY s.UserName,st.Name";
In the other file I call the function it is like this:
List<string> SUsers = _DAO.Selectquery(sql);
When I see the result with a breakpoint, and make a foreach for example:
foreach (string su in SUsers)
{
String str = su;
}
I only see the username, and the others fields disappear. I have change List for IEnumerable and the result is the same.
So I don't know whats is happening.
I would Appreciate your help.
Thank You.
Create a class like this:
public class clients{
private string username;
public string Username
{
get
{
return username;
}
set
{
username = value;
}
}
private string status_name;
public string Status_name
{
get
{
return status_name;
}
set
{
status_name = value;
}
}
private string firstName;
public string FirstName
{
get
{
return firstName ;
}
set
{
firstName = value;
}
}
}
and use List<clients> for your method to map the result.
Edit: if your query is dynamic you can use the dynamic specifications of C#:
create a dynamic entity like this:
public class DynamicClass : DynamicObject
{
private IDictionary<string, object> _values;
public DynamicClass(IDictionary<string, object> values)
{
_values = values;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (_values.ContainsKey(binder.Name))
{
result = _values[binder.Name];
return true;
}
result = null;
return false;
}
}
you can build objects form the class like this:
var values = new Dictionary<string, object>();
values.Add("Username", "value which you read from database");
values.Add("Status_name", "value which you read from database");
values.Add("FirstName","value which you read from database" );
var client = new DynamicClass(values);
and then you can easily access the fields of this class like:
dynamic clientDyn= client ;
var username= clientDyn.Username;
Related
I am using the following Code
public class GetTabelRealizari : ControllerBase
{
public class Realizare
{
String user;
String denumire;
String incasari;
public Realizare(String user, String denumire, String incasari)
{
this.user = user;
this.denumire = denumire;
this.incasari = incasari;
}
public String getUser()
{
return user;
}
public void setUser(String user)
{
this.user = user;
}
public String getDenumire()
{
return denumire;
}
public void setDenumire(String denumire)
{
this.denumire = denumire;
}
public String getIncasari()
{
return incasari;
}
public void setIncasari(String incasari)
{
this.incasari = incasari;
}
}
[HttpPost]
public string Post([FromBody] string[] value)
{
//SSMS connection
string connectionString = "Data Source=DESKTOP-QKC0G7V;Initial Catalog=Restaurant_gest;Integrated Security=True";
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
List<Realizare> realizari = new List<Realizare>();
double incasari;
String incasariString;
SqlCommand command = new SqlCommand("SELECT Users.Username," +
" Tip_Nota_Plata.Denumire," +
" sum(Nota_plata.Suma) as Incasari" +
" from Users" +
" INNER JOIN Nota_plata" +
" INNER JOIN Comandas" +
" ON Nota_plata.Id_comanda = Comandas.Id" +
" ON Comandas.User_Id = Users.Id" +
" INNER JOIN Tip_Nota_Plata" +
" ON Tip_Nota_Plata.Id = Nota_plata.Id_tip_nota" +
" Group by Username, Tip_Nota_Plata.Denumire", connection);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
incasari = (double)reader["Incasari"];
incasariString = incasari.ToString("#.##");
realizari.Add(new Realizare(reader["Username"].ToString(), reader["Denumire"].ToString(), incasariString));
}
}
return JsonConvert.SerializeObject(realizari);
//return "salut";
}
}
And I am receiving an empty JsonObject. Why?
[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]
I keep trying to make it work and I cannot. The list has the objects, i can test it with Console.Writeline(realizari[0].getDenumire()) and it works. I can also serialize a list of strings, it just doesn`t work for objects.
Because the object has no serializable properties.
I'm going to guess you are a Java developer based on this:
String user;
public String getUser()
{
return user;
}
public void setUser(String user)
{
this.user = user;
}
C# has "properties" which, while they compile down to methods very similar to this, the syntax in C# is a bit different. All of the above code can be simplified to a property:
public String User { get; set; }
The usage then becomes simpler as well, allowing for assignments instead of calling a method:
someObject.User = someUser;
In cases where you want to add logic to your getter/setter, you can expand the "auto implemented property" above into a manual one:
private string user;
public string User
{
get { return user; }
set { user = value; }
}
The get and set syntax still tells the compiler that this is a property, but within those blocks you can write any method logic you like. (In the setter value is a keyword for the value being assigned to the property.)
I have Class use as Table in SQL server
Then properties below
[Column(Storage = "_new_name", DbType = "nvarchar (2000)")]
public string new_name { get { return _new_name; } set { _new_name = value; } }
So. Can I get Length From my Class using C#
In this case It's 2000
Thank
You can't easily, without resorting to Reflection. Attributes are meta-data, so they only decorate code with additional information required for various processes. In your case, for your ORM to identify which property maps to which column.
Assuming you have a class like this:
public class TestTable
{
private string _new_name;
private string _address;
[Column(Storage = "_new_name", DbType = "nvarchar (2000)")]
public string new_name {
get
{
return _new_name;
}
set
{
_new_name = value;
}
}
[Column(Storage = "_address", DbType = "nvarchar (5000)")]
public string address {
get
{
return _address;
}
set
{
_address = value;
}
}
}
You can read the attribute values from the properties like this:
var properties = typeof(TestTable).GetProperties();
var attributesPerProperty = new Dictionary<string, string>();
foreach (var propertyInfo in properties)
{
var attribute = System.Attribute.GetCustomAttributes(propertyInfo).FirstOrDefault();
if(attribute is ColumnAttribute)
{
var columnAttribute = (ColumnAttribute)attribute;
attributesPerProperty.Add(propertyInfo.Name, columnAttribute.DbType);
}
}
It's not an ideal way of doing things, and I've just given a rough example but if you really, really need to read this kind of information from your classes, the above will get you there.
I've managed to get something up and running today as small sandbox/POC project, but have seemed to bump my head on one issue...
Question:
Is there a way to get dapper to map to SQL column names with spaces in them.
I have something to this effect as my result set.
For example:
SELECT 001 AS [Col 1],
901 AS [Col 2],
00454345345345435349 AS [Col 3],
03453453453454353458 AS [Col 4]
FROM [Some Schema].[Some Table]
And my class would look like this
public class ClassA
{
public string Col1 { get; set; }
public string Col2 { get; set; }
///... etc
}
My implementation looks like this at the moment
public Tuple<IList<TClass>, IList<TClass2>> QueryMultiple<TClass, TClass2>(object parameters)
{
List<TClass> output1;
List<TClass2> output2;
using (var data = this.Connection.QueryMultiple(this.GlobalParameter.RpcProcedureName, parameters, CommandType.StoredProcedure))
{
output1 = data.Read<TClass>().ToList();
output2 = data.Read<TClass2>().ToList();
}
var result = new Tuple<IList<TClass>, IList<TClass2>>(output1, output2);
return result;
}
Note: The SQL cant be modified in any way.
Currently I'm going through the dapper code, and my only foreseeable solution is to add some code to "persuade" the column comparison, but not having much luck so far.
I've seen on StackOverflow that there are things like dapper extensions, but I'm hoping I can get this done without adding an extention, if not. I'll take whatever is quickest to implement.
There's a nuget package Dapper.FluentMap that allows you to add column name mappings (including spaces). It's similar to EntityFramework.
// Entity class.
public class Customer
{
public string Name { get; set; }
}
// Mapper class.
public class CustomerMapper : EntityMap<Customer>
{
public CustomerMapper()
{
Map(p => p.Name).ToColumn("Customer Name");
}
}
// Initialise like so -
FluentMapper.Initialize(a => a.AddMap(new CustomerMapper()));
see https://github.com/henkmollema/Dapper-FluentMap for more.
One option here would be to go via the dynamic / non-generic API, and then fetch the values out via the IDictionary<string,object> API per row, but that might be a bit tedious.
As an alternative, you can create a custom mapper, and tell dapper about it; for example:
SqlMapper.SetTypeMap(typeof(ClassA), new RemoveSpacesMap());
with:
class RemoveSpacesMap : Dapper.SqlMapper.ITypeMap
{
System.Reflection.ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(System.Reflection.ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
var prop = typeof(ClassA).GetProperty(columnName.Replace(" ", ""));
return prop == null ? null : new PropertyMemberMap(columnName, prop);
}
class PropertyMemberMap : Dapper.SqlMapper.IMemberMap
{
private string columnName;
private PropertyInfo property;
public PropertyMemberMap(string columnName, PropertyInfo property)
{
this.columnName = columnName;
this.property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
System.Reflection.FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return property.PropertyType; }
}
System.Reflection.ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
System.Reflection.PropertyInfo SqlMapper.IMemberMap.Property
{
get { return property; }
}
}
}
I had a similar problem when trying to get mapped results from a call to the system sp_spaceused procedure. Marc's code didn't quite work for me as it complained about not being able to find a default constructor. I also made my version generic so it could theoretically be re-used. This may not be the fastest performing piece of code, but it works for me and in our situation these calls are made infrequently.
class TitleCaseMap<T> : SqlMapper.ITypeMap where T: new()
{
ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return typeof(T).GetConstructor(Type.EmptyTypes);
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
string reformattedColumnName = string.Empty;
foreach (string word in columnName.Replace("_", " ").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
reformattedColumnName += char.ToUpper(word[0]) + word.Substring(1).ToLower();
}
var prop = typeof(T).GetProperty(reformattedColumnName);
return prop == null ? null : new PropertyMemberMap(prop);
}
class PropertyMemberMap : SqlMapper.IMemberMap
{
private readonly PropertyInfo _property;
public PropertyMemberMap(PropertyInfo property)
{
_property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return _property.PropertyType; }
}
ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
PropertyInfo SqlMapper.IMemberMap.Property
{
get { return _property; }
}
}
}
I know this is an old question nevertheless i faced the same problem in my last project, so i just created an own mapper using attributes.
I defined an attribute class called ColumnNameAttribute.cs
using System;
namespace DapperHelper.Attributes
{
[System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
sealed class ColumNameAttribute : Attribute
{
private string _columName;
public string ColumnName
{
get { return _columName; }
set { _columName = value; }
}
public ColumNameAttribute(string columnName)
{
_columName = columnName;
}
}
}
After defining the attribute, i implemeted a dynamic mapper that uses the Query method from Dapper but works as the Query<T>:
using Dapper;
using DapperHelper.Attributes;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Web.Routing;
namespace DapperHelper.Tools
{
public class DynamicMapper<T> :IDisposable where T : class, new()
{
private readonly Dictionary<string, PropertyInfo> _propertiesMap;
public DynamicMapper()
{
_propertiesMap = new Dictionary<string, PropertyInfo>();
PropertyInfo[] propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (propertyInfo.GetCustomAttribute(typeof(ColumNameAttribute)) is ColumNameAttribute columNameAttribute)
{
_propertiesMap.Add(columNameAttribute.ColumnName, propertyInfo);
}
else
{
_propertiesMap.Add(propertyInfo.Name, propertyInfo);
}
}
}
public List<T> QueryDynamic(IDbConnection dbConnection, string sqlQuery)
{
List<dynamic> results = dbConnection.Query(sqlQuery).ToList();
List<T> output = new List<T>();
foreach (dynamic dynObj in results)
{
output.Add(AssignPropertyValues(dynObj));
}
return output;
}
private T AssignPropertyValues(dynamic dynamicObject)
{
T output = new T();
RouteValueDictionary dynamicObjProps = new RouteValueDictionary(dynamicObject);
foreach (var propName in dynamicObjProps.Keys)
{
if (_propertiesMap.TryGetValue(propName, out PropertyInfo propertyMapped)
&& dynamicObjProps.TryGetValue(propName, out object value))
{
propertyMapped.SetValue(output, value);
}
}
return output;
}
public void Dispose()
{
_propertiesMap.Clear();
}
}
}
To use it, you have to refer to your Model class and define the attribute:
using DapperHelper.Attributes;
namespace Testing
{
public class Sample
{
public int SomeColumnData { get; set; }
[ColumnName("Your Column Name")]
public string SpecialColumn{ get; set; }
}
}
and then you can implement something like this:
DynamicMapper<Sample> mapper = new DynamicMapper<Sample>();
List<Sample> samples = mapper.QueryDynamic(connection, "SELECT * FROM Samples");
I hope it can help someone looking for an alternative.
I very new to Linq and Entity frame work, i have problem with my below code. I am getting error
Unable to cast object of type '<>f__AnonymousType1`2
[System.Int64,System.String]' to type 'ConsoleApplication1.Profile'
.
My Code is:
static void Main(string[] args)
{
ProfileEntitiesContext obj = new ProfileEntitiesContext();
List<Profile> list = new List<Profile>();
var test = (from c in obj.Customer
join a in obj.Address
on c.ProfileId
equals a.Customer.ProfileId
select new
{
CustomerProfileId = c.CustomerProfileId,
FirstName = c.FirstName
AddressLine1 = a.Line1
}).ToList().Cast<CustomerConfidentialProfile>();
foreach(var cust in test) // Unable to cast object of type '<>f__AnonymousType1`2
//[System.Int64,System.String]' to type 'ConsoleApplication1.Profile'.
{
list.Add(cust);
}
}
public class Profile
{
int _CustomerProfileId;
string _FirstName;
string _AddressLine1;
public int CustomerProfileId
{
get { return _CustomerProfileId; }
set { _CustomerProfileId = value; }
}
public string FirstName
{
get { return _FirstName; }
set { _FirstName = value; }
}
public string AddressLine1
{
get { return _AddressLine1; }
set { _AddressLine1= value; }
}
}
Any help will be appreciated.
Your problem is that from the LINQ-query you are returning a anonymous type ( by using the new { ... } syntax.
However, you try to jam this object into a List<Profile>. So it's complaining that you are trying to put this anonymous object into a List that only takes Profile objects.
Why just not replace new { ... with new Profile { ... since you are using the same fields in the anonymous type as you do in the Profile type.
And remove ToList and Cast at the end as well.
Thats because the anonymous type <>f__AnonymousType1'2 [System.Int64,System.String] IS NOT Profile! (not an instance and not an instance of ancestor). Try to replace your select like this:
select new CustomerConfidentialProfile
{
CustomerProfileId = c.CustomerProfileId,
FirstName = c.FirstName,
AddressLine1 = a.Line1,
property assignments go futher
})
You can't cast an anonymous type to a named type. But you can construct a named type directly:
select new CustomerConfidentialProfile()
{
CustomerProfileId = c.CustomerProfileId,
FirstName = c.FirstName
AddressLine1 = a.Line1
}).ToList();
I'm accessing a database column where a phone number is stored as a varchar in the format +a-b:c where a = country code, b = phone number and c = extension. E.g. +44-07700123456:123
So I have a type that handles serialization along the lines of:
public struct PhoneNumber {
public PhoneNumber(string val) { /*...*/ }
public override string ToString() { /*...*/ }
public static PhoneNumber TryParse(string val) { /*...*/ }
}
and a POCO:
public class Customer {
public PhoneNumber? HomePhone;
}
Then in my data access code some Linq along the lines of:
public IQueryable<Customers> GetCustomers() {
var customers = (from c in DataContext.Customers
select new Customer {
HomePhone = PhoneNumber.TryParse(c.HomePhone)
});
return customers;
}
So far so good, this all works fine when retrieving records from the database, but my problem is I can't perform a Linq query on the result like:
GetCustomers().Where(c => c != null && c.HomePhone.Value.ToString().Contains("123"));
I get a an error "Method 'System.Nullable`1[PhoneNumber] TryParse(System.String)' has no supported translation to SQL". Now I know I can perform the phone number search in GetCustomers() but this is not ideal.
Is there a way I can let Linq know how to translate my linq to sql? So that I can I do something like GetCustomers().Where(c => c.HomePhone.Value.ToString().Contains("123")) ?
P.S. Not sure on the title of this one, any alternatives are welcome.
The problem is that your PhoneNumber.TryParse() call is getting translated into an expression that's sent up to the server, which it doesn't understand. Furthermore, there's no way to tell SQL about your structure so you won't be able to do a server-side query based on the parsed value. One option is to capture the string value and move the PhoneNumber.TryParse() bit somewhere else. For example:
public class Customer {
public string HomePhoneString;
private bool _HomePhoneParsed;
private PhoneNumber? _HomePhone;
public PhoneNumber? HomePhone
{
get
{
if(!_HomePhoneParsed)
{
_HomePhone = PhoneNumber.TryParse(HomePhoneString);
_HomePhoneParsed = true;
}
return _HomePhone;
}
}
}
public IQueryable<Customers> GetCustomers() {
var customers = (from c in DataContext.Customers
select new Customer {
HomePhoneString = c.HomePhone
});
return customers;
}
And then you can either query server-side:
GetCustomers().Where(c => c.HomePhoneString != null && c.HomePhoneString.Contains("123"))
Or client-side:
GetCustomers().AsEnumerable()
.Where(c => c.HomePhone != null && c.HomePhone.Value.Contains("123"))
Following up on this, an alternative solution is to change PhoneNumber to a class and add a 'Value' property to serialize/deserialize like:
public class PhoneNumber {
public override string ToString() { /*...*/ }
public Parse(string val) { /*...*/ }
public string Value {
get {
return ToString();
}
set {
Parse(value);
}
}
}
This kind of code is not really suitable for a property but it does allow you to initialize the HomePhone object in the Linq query like:
var customers = (from c in DataContext.Customers
select new Customer {
FirstName = c.FirstName,
HomePhone = new PhoneNumber {
Value = c.HomePhone
}
});
Which then means you can use the serializer like:
customers.Where(x => x.HomePhone.Value.Contains("123"));