Serialize dynamic Dapper result to CSV - c#

I'm trying to serialize a dynamic Dapper result to CSV using ServiceStack.Text, but I'm getting a collection of line breaks. According to ServiceStack.Text, it can handle both anonymous and IDictionary<string, object> types.
using (var conn = new SqlConnection(...))
{
var data = conn.Query("select * from data");
var output = CsvSerializer.SerializeToCsv(data);
Console.WriteLine(output);
Console.Read();
}
When I use the same type, it works.
IEnumerable<dynamic> list = new List<dynamic>
{
new
{
Name = "Nathan",
Id = 1,
Created = DateTime.UtcNow
}
};
Console.WriteLine(CsvSerializer.SerializeToString(list));
Console.Read();
What am I missing about Dapper's return type?
I know I can solve this by projecting onto a model class, but the beauty of my approach lies in the use of dynamics. Do I have any options?

Dapper's Query method returns IEnumerable<dynamic>, which is basically: IEnumerable<object> - where each row happens to implement IDictionary<string,object>. I wonder whether SS is looking for the T is IEnumerable<T>: in which case, yeah, that won't work well. You could try:
var typed = data.Select(x => (IDictionary<string,object>)typed);
var output = CsvSerializer.SerializeToCsv(typed);
This does the cast in the projection, so that if SerializeToCsv is a generic method, it'll know about the interface support.
Dapper does not return anonymous types.

dynamic Generic IDictionary's like what Dapper returns should now be supported from this commit.
This change is available from v4.0.43+ that's now available on MyGet.

Related

ORMLite SqlList with Tuples

I'm having some troubles selecting a Tuple of Objects from my custom SQL query with ORMLite.
I have the following code:
var query = "select definition.*, timeslot.*, type.* from <blah blah>";
var defs = dbConnection.SqlList<Tuple<Definition, Timeslot, Type>>(query, new
{
/* query parameters */
});
The query itself is fine (I've tested it in SQL Management Studio).
The code above sets attributes only for the first item of the Tuple, leaving to the default state the others.
I've selected singularly each object and the result is correct (so no trouble during the conversion to POCO I guess).
Same thing goes if I use Select<Tuple<Definition, Timeslot, Type>> instead of SqlList.
I couldn't manage to try with MultiSelect since it appears to not take a string.
What is the correct way to select a Tuple in this manner?
I am working in C#.
Thanks in advance!
SelectMulti seems to be what you're looking for here.
From the documentation under the Selecting multiple columns across joined tables heading:
// Note: I'm making an assumption on your query here.
// Build the `q` object however it needs to be.
var q = db.From<Definition>()
.Join<Definition, Timeslot>()
.Join<Definition, Type>();
var results = db.SelectMulti<Definition, Timeslot, Type>(q);
foreach (var tuple in results)
{
var definition = tuple.Item1;
var timeslot = tuple.Item2;
var type = tuple.Item3;
}

FileHelperEngine returns List<object> instead of List<T>

I'm using FileHelper nuget package to parse a flat file into custom DTO list class. In the beginning of my development, I hard coded the FixedFieldLength in a class file which had the list of members declared and I used that class to build the filehelperengine, but later we decided to create the field length dynamically and used below code to create the classBuilder
private FixedLengthClassBuilder BuildFixedLengthClass(string mplFileType)
{
var layoutDetails = GetLayoutDetailsFromDatabase();
const string className = "My_Dynamic_Class";
var fixedLengthClassBuilder = new FixedLengthClassBuilder(className);
foreach (var column in layoutDetails)
{
dynamic dynamicColumn = column;
fixedLengthClassBuilder.AddField(dynamicColumn.FieldName,
dynamicColumn.NumberOfCharacters, dynamicColumn.Data_Type);
if (dynamicColumn.Data_Type == "DateTime")
{
fixedLengthClassBuilder.LastField.Converter.Kind =
FileHelpers.ConverterKind.Date;
fixedLengthClassBuilder.LastField.Converter.Arg1 = "yyyyMMdd";
}
}
return fixedLengthClassBuilder;
}
Now, I use the object returned from above method to create the FileHelperEngine as below
var fileHelperEngine = new FileHelperEngine(classBuilder.CreateRecordClass())
var parseResult = fileHelperEngine.ReadFileAsList(fileName);
Now, the parseResult will be List<object> where it has to be List<T>
The fileHelperEngine returns List<T> when we do not pass the classBuilder.CreateRecordClass()
Because of this, I had to loop each records and convert to respective type. I believe, I can't use Automapper even to convert, because object's properties are not visible to be converted.
Is this something needs to be added in this library, or is that something I'm missing?
Try using Cast<T>() (with the desired class inserted for T):
var parseResult = fileHelperEngine.ReadFileAsList(fileName).Cast<T>();
// if desired then add .ToList() or .ToArray()

Can't find property or field on a dynamic object

I using Dynamic Linq to do some database queries and it's working really well up to now. I can pass a string to a Select to select fields like so:
var output = myDatabaseTable.Select("Foo, Bar");
For example. The power obviously being when you pass a string variable rather than hardcoded strings. The problem I'm running into now is that the library using IEnumerable instead of IEnumerable<T> because, obviously, it can't know T until runtime. I'm using this to select data and eventually return it to a client and it works fine for spitting out raw data, but now I want to be able to do some more processing before returning the data and that requires getting the query to run on the database first. I can do something like this:
var materializedResults = output.Cast<dynamic>().ToList();
And that will make the query run. But the problem is, once I've done that, it seems I can't use dynamic linq anymore. For example, if I did something like this:
var foos = materializedResults.Select("Foo");
I now get a System.Linq.Dynamic.ParseException with the message No property of field 'Foo' exists in type 'Object' (Note: I can see in the debugger that the materializedResults does actually have all the expected properties).
So after casting to a List so I can potentially iterate through it and modify some of the values, I can no longer query it.
So my question is, how can I take a dynamic query (with select, group by, order by etc provided as strings), materialize the results and then actually process those result dynamically?
I thought maybe if I could cast to the actual type rather than dynamic it might work, so I tried this:
var d = output.Cast<dynamic>().ToList();
MethodInfo method = typeof(Enumerable).GetMethod("Cast", new[] {typeof(IEnumerable)});
method = method.MakeGenericMethod(d.First().GetType());
output = method.Invoke(d, new[] {d}) as IEnumerable;
Which is ugly and requires me to cast twice. The first time to dynamic so I can get the type from the first item then again to that type.
If you do YourStuff.Cast<dynamic>.ToList(), you will receive IEnumerable<object>, and there is no property Foo on the type object.
The question you might be asking, how can you get IList<TheActualType>?! You can do it this way:
// for IEnumerable
public static IList ToAnonymousList(this IEnumerable enumerable)
{
var enumerator = enumerable.GetEnumerator();
if (!enumerator.MoveNext())
throw new Exception("?? No elements??");
var value = enumerator.Current;
var returnList = (IList) typeof (List<>)
.MakeGenericType(value.GetType())
.GetConstructor(Type.EmptyTypes)
.Invoke(null);
returnList.Add(value);
while (enumerator.MoveNext())
returnList.Add(enumerator.Current);
return returnList;
}
// for IQueryable
public static IList ToAnonymousList(this IQueryable source)
{
if (source == null) throw new ArgumentNullException("source");
var returnList = (IList) typeof (List<>)
.MakeGenericType(source.ElementType)
.GetConstructor(Type.EmptyTypes)
.Invoke(null);
foreach (var elem in source)
returnList.Add(elem);
return returnList;
}
It's a simple extension method that can later be used, as such:
var test = (new[]
{
new
{
Property1 = "10",
Property2 = "10",
Property3 = 1
}
}
.Select("New(Property1, Property2)"))
.ToAnonymousList();
Your Cast is Defaulting to which will cause an error
(output as System.Collections.Generics.IEnumerable)
This Cast Specified the Correct Interface Try again
(output as System.Collections.IEnumerable).Cast<dynamic>().ToList()

Convert anonymous type to array or arraylist. Can it be done

Trying to retrieve data using linq from a database. I would like to use anonymous types and convert to an Ilist, Array, ArrayList or Collection. The data is used in a third party object that accepts Ilist, arraylist or collections.
I can't seem to get this to work. I get the following error, "Sequence operators not supported for type 'System.String'"
using (var db = new dbDataContext())
{
var query = from e in db.people
select new
{
Count = e.LastName.Count()
};
Array test;
test = query.ToArray();
}
It's got nothing to do with converting the results to array lists, or even anonymous types. Here's another version of your code which will fail:
using (var db = new dbDataContext())
{
var query = db.people.Select(x => x.LastName.Count());
foreach (int x in query)
{
Console.WriteLine(x);
}
}
That will still fail in the same way - because it's the translation of this bit:
x => x.LastName.Count()
into SQL which is causing problems.
Change it to:
x => x.LastName.Length
and I suspect you'll find it works. Note that this isn't really a C# issue - it's just LINQ to SQL's translation abilities.
I would suggest that you don't use an anonymous type here though - it's pointless. Maybe this isn't your complete code, but in general if you find yourself creating an anonymous type with a single member, ask yourself if it's really doing you any good.
The ArrayList class has a constructor that accepts ICollection.
You should be able to feed it a List version of your LINQ result.
using (var db = new dbDataContext()) {
var query = from e in db.people
select new { Count = e.LastName.Count() };
ArrayList list = new ArrayList(query.ToList());
}
I don't have Visual Studio here (I'm on my Mac), but it might be of help.
(ToArray should suffice as well)
You might need to replace your Count() by Length.

Using Linq to run a method on a collection of objects?

This is a long shot, I know...
Let's say I have a collection
List<MyClass> objects;
and I want to run the same method on every object in the collection, with or without a return value. Before Linq I would have said:
List<ReturnType> results = new List<ReturnType>();
List<int> FormulaResults = new List<int>();
foreach (MyClass obj in objects) {
results.Add(obj.MyMethod());
FormulaResults.Add(ApplyFormula(obj));
}
I would love to be able to do something like this:
List<ReturnType> results = new List<ReturnType>();
results.AddRange(objects.Execute(obj => obj.MyMethod()));
// obviously .Execute() above is fictitious
List<int> FormulaResults = new List<int>();
FormulaResults.AddRange(objects.Execute(obj => ApplyFormula(obj)));
I haven't found anything that will do this. Is there such a thing?
If there's nothing generic like I've posited above, at least maybe there's a way of doing it for the purposes I'm working on now: I have a collection of one object that has a wrapper class:
class WrapperClass {
private WrappedClass wrapped;
public WrapperClass(WrappedClass wc) {
this.wrapped = wc;
}
}
My code has a collection List<WrappedClass> objects and I want to convert that to a List<WrapperClass>. Is there some clever Linq way of doing this, without doing the tedious
List<WrapperClass> result = new List<WrapperClass>();
foreach (WrappedClass obj in objects)
results.Add(new WrapperClass(obj));
Thanks...
Would:
results.AddRange(objects.Select(obj => ApplyFormula(obj)));
do?
or (simpler)
var results = objects.Select(obj => ApplyFormula(obj)).ToList();
I think that the Select() extension method can do what you're looking for:
objects.Select( obj => obj.MyMethod() ).ToList(); // produces List<Result>
objects.Select( obj => ApplyFormula(obj) ).ToList(); // produces List<int>
Same thing for the last case:
objects.Select( obj => new WrapperClass( obj ) ).ToList();
If you have a void method which you want to call, here's a trick you can use with IEnumerable, which doesn't have a ForEach() extension, to create a similar behavior without a lot of effort.
objects.Select( obj => { obj.SomeVoidMethod(); false; } ).Count();
The Select() will produce a sequence of [false] values after invoking SomeVoidMethod() on each [obj] in the objects sequence. Since Select() uses deferred execution, we call the Count() extension to force each element in the sequence to be evaluated. It works quite well when you want something like a ForEach() behavior.
If the method MyMethod that you want to apply returns an object of type T then you can obtain an IEnumerable<T> of the result of the method via:
var results = objects.Select(o => o.MyMethod());
If the method MyMethod that you want to apply has return type void then you can apply the method via:
objects.ForEach(o => o.MyMethod());
This assumes that objects is of generic type List<>. If all you have is an IEnumerable<> then you can roll your own ForEach extension method or apply objects.ToList() first and use the above syntax .
The C# compiler maps a LINQ select onto the .Select extension method, defined over IEnumerable (or IQueryable which we'll ignore here). Actually, that .Select method is exactly the kind of projection function that you're after.
LBushkin is correct, but you can actually use LINQ syntax as well...
var query = from o in objects
select o.MyMethod();
You can also run a custom method using the marvelous Jon Skeet's morelinq library
For example if you had a text property on your MyClass that you needed to change in runtime using a method on the same class:
objects = objects.Pipe<MyClass>(class => class.Text = class.UpdateText()).ToList();
This method will now be implemented on every object in your list. I love morelinq!
http://www.hookedonlinq.com/UpdateOperator.ashx has an extended Update method you can use. Or you can use a select statement as posted by others.

Categories