Specifying properties to be updated in linq query - sql

I want to be able to specify the properties to get populated/updated in the linq expression.
Something in the following fashion:
Proxy.UpdateEmployee(List<string> propertiesNames)
Proxy.GetEmployee() //inside the method populate only certain properties
The return values must be of known type(no anonymous types accepted).
DLINQ enable to select by specifying properties' names but the result is IQueryable interface and I'm unable to AsEnumerable() it in order to build the known type query afterwards.

You have to use reflection to modify instance properties by name.
So wherever you're updating your object with LINQ you need to do something like this:
foreach (string propName in propertiesNames)
{
PropertyInfo prop = this.GetType().GetProperty(propName);
prop.SetValue(valueForProp);
}

Related

How to update two columns with same name from two tables in a join query

I am getting an error:
Property or Indexer cannot be assigned to "--" it is read only
when trying to update two columns with the same name in two tables in a join query. How do I get this to work? Thanks!
The anonymous object created in your projection ("select new" part) is read-only and its properties are not tracked by data context by any means.
Instead, you can try this:
//...
select new
{
p1 = p,
p2 = t
}
foreach (var row in updates)
{
row.p1.Processed = true;
row.p2.Processed = true;
}
In order to improve performance you may also want to take a look at batch update capabilities of Entity Framework Extensions (if you are using Entity Framework): https://entityframework-extensions.net/overview
Yes, that's due to anonymous type properties are read only, from documentation:
Anonymous types provide a convenient way to encapsulate a set of
read-only properties into a single object without having to explicitly
define a type first.
I suggest you to create a custom class with the two entities you need (a DTO):
public class PassengerDTO
{
public Passenger Passenger {get;set}
public PassengerItinerary PassengerItinerary {get;set}
}
And use it in your projection, You need the entity instances and not just the properties you want to modify because, when you modify the Processed property in the foreach the proxy class that represent your entity is going to change the status of you entity to Updated.

AliasToBean DTO with known type

All the examples I am finding for using the AliasToBean transformer use the sessions CreateSqlQuery method rather than the CreateQuery method. They also only return the basic value types, and not any object's of the existing mapped types.
I was hoping it would be possible that my DTO have a property of one of my mapped Domain objects, like below, but I am not getting traction. I get the following exception:
Could not find a setter for property '0' in class 'namespace.DtoClass'
My select looks like the following on my mapped classes (I have confirmed the mappings pull correctly):
SELECT
fcs.MeasurementPoint,
fcs.Form,
fcs.MeasurementPoint.IsUnscheduled as ""IsVisitUnscheduled"",
fcs.MultipleEntryAllowed
FROM FormCollectionSchedule fcs
My end query will be more complex, but I wanted to confirm if this AliasToBean method can return mapped domain objects as well as basic field values from tables retrieved via sql.
the query execution looks like the following:
var result = session.CreateQuery(hqlQuery.ToString())
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof (VisitFormCollectionResult)))
.List<VisitFormCollectionResult>();
note: the VisitFormCollectionResult DTO has more properties, but I wanted to know if I could populate the domain object properties matching the names
update found my problem! I have to explicitly alias each of the fields. once I added an alias, even though the member property on the class matched my DTO's property name, the hydration of the object worked correctly.
The answer to my own question was that each of the individual fields in the select needed an explicit alias matching the property, regardless if the field name already matched the property name of the DTO object:
SELECT
fcs.MeasurementPoint as "MeasurementPoint",
fcs.Form as "Form",
fcs.MeasurementPoint.IsUnscheduled as "IsVisitUnscheduled",
fcs.MultipleEntryAllowed as "MultipleEntryAllowed"
FROM FormCollectionSchedule fcs

WCF DataServiceQuery for derived type

I have a base entity, and a derived entity, with an extra boolean property. My WCF Data Service exposes an EntitySet of the base entity. I can query it in a browser:
http://myserver/myservice/BaseSet/Namespace.Derived()?$filter=(BoolProp eq false)
And I get a collection of objects of my Derived type. All good.
In my client I have a grid which takes a DataServiceQuery. So I constructed my query:
var query = context.CreateQuery<Proxy.Derived>("BaseSet");
But when I try to filter on derived properties it returns an error. And when I examined the URL it used in its request it's missing the chunk for my derived type, i.e. it looked like:
http://myserver/myservice/BaseSet()?filter=(BoolProp eq false)
What's the proper way to construct a DataServiceQuery that I can use to query using properties on my derived type?
Turns out all I needed was to extend the entitySetName argument to include my derived type:
var query = context.CreateQuery<Proxy.Derived>("BaseSet/Namespace.Derived")();
The name of the argument isn't great. Now I actually bother to read the documentation it does tell me that the entitySetName should be "A string that resolves to a URI." Not sure that helps most people but I should have checked it sooner.

Why isn't this Linq query on Dictionary<TKey, TValue> working as DataSource

I have the following in VB:
Dim sources = From source In importSources Select New With _
{.Type = source.Key, .Source = source.Value.Name}
dgridSourceFiles.DataSource = sources
When I debug, sources shows an in-memory query and has 2 records within. Yet the datagrid view will not show the records.
So why won't this work? suggestions can be either VB or C#...
Update
When I use:
Dim sources = (From source In importSources Select New With _
{.Type = source.Key, .Source = source.Value.Name}).ToList()
...the datasource is displayed.
Your LINQ query is lazily evaluated and implements the IEnumerable<T> interface only (as far as I know), which means its results are not established until an enumerator calls MoveNext somewhere (as happens within a foreach loop, for example).
It seems the DataSource property does not enumerate its contents in this way. It's completely expecting an implementation of IList (or one of a few other interfaces—see below) so that it can access items by index. This is used internally by the control for sorting, filtering, etc. With this in mind, it's likely that all setting the DataSource property does is check the object's type to see whether it implements any of the supported interfaces. So I don't think the DataSource property is designed to deal with this type of object (a lazily evaluated query) at all.
Now, that ToList call populates a List<T> with the results of your query; this does implement IList and can therefore be used as the DataSource.
My understanding is that the reason DataSource is typed merely as object is that it expects any of the following interfaces:
IList
IListSource (in which case the IListSource.GetList method is used together with the DataMember property to provide data to the control)
IBindingList (which propagates changes in the list to the control for UI updates)
IBindingListView (like BindingSource)
This is according to the MSDN documentation.
You may need to call DataBind after setting the source. Try:
dgridSourceFiles.DataSource = sources
dgridSourceFiles.DataBind()

Linq to SQL intellisense has no knowledge of tables within the datacontext object

I can successfully connect to the database with my datacontext object. I am able to read and write to the database successfully, however I can't use the same syntax that others appear to be using.
For example, when I want data from a table, I have to do something like this:
db = new UserDataDataContext(WebConfigurationManager.ConnectionStrings["UserData"].ConnectionString);
IQueryable Users = db.GetTable<User>();
I'd like to be able to write linq queries like how I see others doing them:
db = new UserDataDataContext(WebConfigurationManager.ConnectionStrings["UserData"].ConnectionString);
var query = from u in db.User
where u.UserName == "Test"
select u;
But intellisense does not recognize User as an property of db, and thus won't compile. Intellisense doesn't show any properties that look related to tables or entities of my database.
Here is the error message I am getting:
'System.Data.Linq.DataContext' does not contain a definition for 'User' and no extension method 'User' accepting a first argument of type 'System.Data.Linq.DataContext' could be found (are you missing a using directive or an assembly reference?)
Here is a rundown of what I am doing:
I used the database designer, dragged the tables in that I wanted.
Then I saved it as a dbml file.
It then created the new class that extends dataContext for me, named UserDataDataContext. I then instantiate a new instance of UserDataDataContext named db, passing in my connection string from Web.config.
Then I try to write a linq query referencing table names as properties of the db object, but it does not recognize them.
I can't seem to find what I am doing wrong compared to all of the examples I've read. Any ideas?
I'm sure you have the following variable declaration somewhere:
// variable is of type System.Data.Linq.DataContext
DataContext db;
Change it to:
// variable is now of the appropriate subclass's type
UserDataDataContext db;
If db is a local variable and you can afford to inline the initialization and declaration together, it would be even better to use implicit typing instead:
// db is implicitly of type UserDataDataContext
var db = new UserDataDataContext(WebConfigurationManager.ConnectionStrings["UserData"].ConnectionString);
C# is a safe and statically typed language. Although the object referred to by your reference will indeed, at run-time, have the properties you are expecting, the compiler won't let this compile because these properties don't exist on the variable's type.