Subsonic custom collection type - c#

This may seem like a simple question however i've spent the last hour trying to solve this.
I want to create a custom subsonic collection so that i can fill it with data from a query with multiple joins using the .ExecuteAsCollection<>(); method.
i've created the custom class and a custom collection and even a controller with the load method but i keep getting a null refernce exception from the ExecuteAsCollection<>();
the stack track says its an error coming from the SubSonic.Load method.
i have left out the class's "SQLProps" that all the other subsonic classes have, but i was hoping i wouldn't have to go through each field painstakingly.
There has to be something simple i'm missing. Can someone who's done this give me a quick run down on what is required by subsonic to fill a custom collection with a query?
thanks
Doug
UPDATE:
i forgot to mention that i also added the public Columns struct with all my columns.

ExecuteAsCollection<T>() will only work with SubSonic-generated collections. You can map the result of a query to an arbitrary object type with ExecuteTypedList<T>(). This will match the columns returned from your query to properties of type T with the same name and give you List<T>.

Related

List<dynamic> does not return structure

I got a public property of List<dynamic> type.
This property is getting populated with same type of objects in the list. I am using a third party reporting tool to design a report by data returned by this property.
When the List object contains data, I am able to see the required properties/structure to design the report. Whereas when there is no data I do not see any properties to create the report layout.
Any help would be greatly appreciated.
Thanks for your help.
Well, that is obviously true. dynamic properties are evaluated at run time. If there is no data to show, there is no way to know what type of object, struct or anything else would actually go in there. So reflection is not able to determine anything about the type at that moment. (I don't have to say that using reflection on dynamic types is dangerous to start with, since the type can change at any time without any warning.)
The solution is to ensure there is always data so reflection can determine the types on the data provided, or preferably don't use dynamic at all.

Merging Objects of different types

I have two objects (WS.Customer and EF.Customer). The reason for this is my vendor didn't expose all of the fields in their object (WS.Customer) and I need to insert and update into those fields.
I need to merge WS.Customer -> EF.Customer and later merge EF.Customer -> WS.Customer. EF.Customer will have some extra fields that WS.Customer won't have, but when the field names match - I want the values merged.
I also only want to merge values where the destination field is null, empty, or a default value in case of a Guid.
I know I could use to Linq to query each object and build the other, but is there a less verbose way of doing things? I have some other objects I need to use this approach for and don't feel like spending a weeks typing away.
Thanks
You can use one of the available object-to-object mappers library like AutoMapper or EmitMapper. They will take care of copying the data in both directions and skip fields if properly configured. For example with EmitMapper your code might look like this:
ObjectMapperManager.DefaultInstance
.GetMapper<WS.Customer, EF.Customer>(<your configuration object here>)
.Map(customerSource, customerDestination);
What do you mean by "merged"? I guess you need to "translate" from one instance to another, i.e. copy values when name and type of property matches. Please have a look at the implementation provided in ServiceStack, the extension method of object - TranslateTo method: https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Common/ReflectionExtensions.cs#L31

How to use Projections with references?

I have a mapping that has two references to two other mappings.
Firstly, would I create sub-criteria or create aliases?
So I have:
Base.Property1
Base.Property2
Base.Reference1.Property1
Base.Reference1.Property2
Base.Reference2.Property1
Base.Reference2.Property2
I want to project my query to just these 6 properties.
I have managed to use Projections on a query on just one table, but I'm having difficulty when it comes to multiple tables.
would I do something like (for each reference):
criteria.CreateCrtieria(bla)
.SetProjection(Projections.ProjectionList()
.Add(/*Add projections*/))
.SetResultTransformer(Transformers.AliasToBean(type));
Or just create aliases and have projections on the original criteria like so:
criteria.CreateAlias("reference1", "r1").CreateAlias("reference2", "r2")
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("baseProperty1")
.Add(Projections.Property("r1.property1")
.Add(Projections.Property("r2.property2")) /*etc*/
.SetResultTransformer(Transformers.AliasToBean(baseType));
I don't know if the previous two ideas actually work - they don't seem to, but I don't know if that's because I've forgotten something or if they're along totally the wrong lines.
Thanks.
Using the CreateAlias methods on the Criteria API allow you to join across to your referenced objects and allow you to project out the properties.
You assign each referenced type an alias which you then use to access the properties of the referenced objects.
Also please be aware that you need to make sure the names of the properties in the object you are projecting into are an exact match in the projection list.
You can also specify the JoinType on the CreateAlias methods as well should you want to force a InnerJoin instead of a LeftJoin.
var query = session.CreateCriteria<Base>()
.CreateAlias("Base.Reference1","ref1")
.CreateAlias("Base.Reference2","ref2")
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("Base.BaseProperty"),"DtoBaseProperty")
.Add(Projections.Property("ref1.property1"),"DtoProperty1")
.Add(Projections.Property("ref2.property2"),"DtoProperty2")
)
.SetResultTransFormer(Transformers.AliasToBean(typeof(ProjectionDto)))
.List<ProjectionDto>();
public class ProjectionDto{
public string DtoBaseProperty;
public string DtoProperty1;
public string DtoProperty2;
}
My solution ended up requiring me to write a new Transformer. I'm not going to paste the code because it's fairly long and at the moment quite hacky. But for anyone interested:
Rather than doing .Add(Projections.Property("r1.property1")
I did .Add(Projections.Property("r1.property1"), "SubType.Property1")
Then in the transformer the alias "SubType.Property1" has a tuple value associated with it. I split the alias up and construct a SubType, and for any aliases associated with it, do the same as what the existing transformer does (assign values to those properties on that type), and then finally set the subtype object as a value to the property on the base type.
It's probably completely against the concept of Projections but it works, and works quite well, considering it was hacked together in a couple of hours.

How to bind a telerik grid column to a child data object that is a list?

I have a grid that binds a number of child data objects to columns with no issue, using the syntax defined at http://www.telerik.com/help/aspnet-ajax/grdbindingtosubobjects.html.
What I can't figure out, however, is how to aggregate a child object that is a list or collection. For example, if I have a Customer object and I want to get the customer's first street address, I would use DataField="Customer.Addresses[0].Street" on a standard GridBoundColumn.
How can I get the count of the addresses? I have tried all sorts of GridCalculatedColumn DataFields and Expressions, to no avail. I am looking for something along the lines of this:
That doesn't work, of course. In fact, if I try to do a Count on any dotted data field, I get an exception of
"System.Data.SyntaxErrorException: Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier."
For example, just trying to use an expression of Count({0}) with DataFields set to Customer.FirstName (of which there is only one), causes that exception to be thrown at runtime. Doing the same thing with a non-dotted data field, such as SendDate, does not cause the same exception.
Seems like you already received an answer to this question from the Telerik forums but for people that might stumble upon this question looking for an answer.
Essentially the RadGrid does not support having Collections in its DataFields, and the supported bindable property types can be found here. So in terms of this aggregation you could either do a calculation across this collection before binding it to the RadGrid and have an aggregate column defined, or you could look into using footers much like in this demo.

Viewing a database over Collections, ORM Lists

I've been researching to find out how and what to use to get say the name's of the fields in a class, then to invoke that class and get the properties of the class, as in the field values.
Give you an example, Say if I one to get one value from one record from one table, I would create an object of that class as in;
DBTable<cars> cartable = new DBTable<cars>(1) //passing 1 is a dataset number
cartable.GetLastRec(); OR cartable.Attributes.Key.carIdx // record index
cartable.GetKeyRec();
// Now I print the value
Console.WriteLine("Car number: " + cartable.Attributes.Data.number;
It's easy to get one record, it's like an Object Orientated Database but not sure if it isn't, I don't have any knowledge of the database system, just that the classes are used to talk to a DLL file and pass some numbers.
so far I've been testing with collections, inheriting, ORM, and nothing seams to be able to describe the very simple process going on, Even dynamic invoking objects and iterating over it's attributes
What I hope do is;
Datagridview => Table Classes => DLL entry points => Database
If anyone has had the same challenge or maybe I have the wrong approach here, but completely lost at this stage, Any Idea's welcome
Thanks in Advance
btw: I'm using VS2005, .NET 2.0
The only way to do this is by providing your own PropertyDescriptorCollection.
A search here or on Google, should point you in the correct direction.

Categories