DbContext.Database.SqlQuery returns some null objects - c#

Using Entity Framework 6, the code below queries a table (really, a view) and returns some number of rows. The number of rows is correct, but many of the rows are null, i.e. some of the Licenses objects are null, as seen in the Visual Studio Watch window. I think what is happening is that if any column of a given row in the view contains a null, then the entire row is being set to null.
Any ideas on how to get all the correct data?
String query = "select * from dbo.v_Licenses where [Number] like '%ab%'";
System.Data.Entity.Infrastructure.DbRawSqlQuery<Licenses> dbRawSqlQuery = db.Database.SqlQuery<Licenses>(query);
Queryable<Licenses> licenses = dbRawSqlQuery.AsQueryable();

Be sure that License properties'name are identical with columns that are fetched from the select and property type are identical, too.
Like this:
Select CustomerId,Firstname from Customers
public class Customer
{
public int CustomerId{get;set;}
public string Firstname {get;set;}
}
and change System.Data.Entity.Infrastructure.DbRawSqlQuery to List
I used this approach a lot and it worked very nice for me.

Based on this question it seems like EF (at least at one point) returned null objects if the first column of the result set was null. So rather then selecting * you should explicitly name the columns and ensure that the PK (or some other column) is first.

In my case it did not work because I did NOT have the fields as properties. Once I converted the fields to properties it worked just fine.

Related

Get value of first column without knowing name

Similar to Column Number rather than Column Name but I believe it's different because that was for unnamed columns, whereas my columns are named, I just don't know the names ahead of time.
First, some background. I'm creating a method that takes a query and its arguments as parameters, then runs the query (using Dapper) and checks if the first row, first column value is a 1 or a 0. It's intended to work as a generic validator for databases.
For example, the user could enter a query that returns a 1 in the only row's only column if some value exists in some table, and a 0 otherwise. The use of this method is intentionally very broad and most of the effort is put on the user writing the query (I should also clarify that the "user" in this case is always another developer and the use is done within code calling this method, not on, say, form input).
I want to query my database and get the value of the first row, first column without knowing the name of the column ahead of time. Ideally (though I'm not sure if this is possible or not within the Dapper call), I'd also like to require that there only be one row and one column in the result. When I was searching around, I based my initial solution on this post's first answer, but found that for that to work I needed to know the name of the column:
var dict = connection.Query(query, parameters).ToDictionary(row => (string)row.VALUE);
if(dict.ElementAt(0).Value != 1){
//do stuff
}
I thought of just adding a requirement that the user add an alias that names the first column some constant value (in this case, VALUE), but I'd prefer not to put the burden on my user if at all possible.
Ultimately my core issue is: how can I get the value of a named column in a DB using Dapper without knowing the name of the column?
Does anybody have any ideas?
I've done this successfully by just using int as the type in the generic Query method as such:
int value = conn.Query<int>(sql,
commandType: CommandType.StoredProcedure).FirstOrDefault();
Notice the use of the FirstOrDefault method. So you get 0 or whatever the value is from the DB.
The easiest thing to do would be to make sure the SQL command ALWAYS returns the same column name, by way of an alias. Then your C# code can just use that alias.
Using Tortuga Chain
var result = DataSource.Sql(query, parameters).ToInt32().Execute();
I'd also like to require that there only be one row and one column in the result
By default, Chain uses DbCommand.ExecuteScalar. This returns the first column of the first row, ignoring everything else. To add that restriction I would do this:
var result = DataSource.Sql(query, parameters).ToInt32List().Execute().Single;
Another option is to change how you generate the SQL. For example,
var filterObject = new {ColumnA = 1, ColumnB = "X", ColumnC = 17};
var result = DataSource.From(tableName, filterObject).ToInt32(columnName).Execute();
This has the advantage of being immune to SQL inject attacks (which is probably a concern for you) and ensures that you SQL only returns one column before it is executed.

How to display the string Enum values instead of the number value using SQL

I'm trying to display a list of all Deliveries with the status Dispatched. However, its only returning the number value of the status as opposed to the actual string value. I think this is because I have used Enum to store my status values?
I wish to display the word Dispatched instead of the number value that it represents in the Enum. 
I'm developing in ASP.Net MVC and I'm using the query builder in VS2013.
I'm not sure how to approach this, can anyone please suggest an easy to understand solution using SQL.
Let me know if any additional code is required, and thank you in advance!
Here's the Query I want but it doesn't work:
SELECT Delivery.[Status],
COUNT(Delivery.DeliveryID) AS Dispatched_Status
FROM Delivery
WHERE Delivery.[Status] = 'Dispatched'
GROUP BY Delivery.[Status];
Here's the Query that does work but returns a number value. I tried it this way because Enum stores the string value as a number:
SELECT Delivery.[Status],
COUNT(Delivery.DeliveryID) AS Dispatched_Status
FROM Delivery
WHERE Delivery.[Status] = '1'
GROUP BY Delivery.[Status];
P.S I'm aware that status is a reserved word - will be following the correct naming conventions in future.
Delivery Table Definion
It sounds like you just need to add a lookup table in you DB. Something like
CREATE TABLE [dbo].[StatusLookup](
[StatusID] [int] NOT NULL,
[StatusName] [varchar](64) NOT NULL,
[StatusDescription] [varchar](max),
)
INSERT INTO [dbo].[StatusLookup]([StatusID],[StatusName],[StatusDescription]
VALUES(1, 'Dispatched', 'A dispatched record')
...
Note you'll have to manually do this and make sure to populate it with values that match up with your enum.
Then your query would be
SELECT StatusLookup.[StatusName],
COUNT(Delivery.DeliveryID) AS Dispatched_Status
FROM Delivery
JOIN StatusLookup ON Delivery.Status = StatusLookup.StatusID
WHERE StatusLookup.[StatusName] = 'Dispatched'
GROUP BY StatusLookup.[StatusName];
Enums are stored as integers by default.
You can add a separate varchar or nvarchar field to your database table to hold the description of the enum, and populate it using something like the below:
string selectedEnumDescription = Enum.GetName(typeof(DeliveryStatusEnum), Delivery.Status)
The exact implementation depends on how you are saving your records, and what the actual properties and enum names are.
You can then just select the description column in your SQL query.
Either that or you could store the actual enum values and descriptions within a separate table and do a join.
You can store enum in database as a number, usually a small number - the exact type depends on your database. When you read it - you convert a number to enum and work in your code with the enum. When you need to display it, you can call a ToString() method on that enum, for example
public enum Foo
{
A,
B
}
public class Program
{
public static void Main()
{
Console.WriteLine(Foo.A.ToString()); // Prints A
}
}
See it working
You can also use description attribute and print that, see examples here and here

Linq to SQL SubmitChanges only for specific table

I have been using linq to sql for a little while and often come up against this type of problem....
e.g
I have 2 db tables
-Table: Invoice ("Id" int auto-increment, "InvoiceDate" datetime)
-Table: InvoiceItems ("Id" int auto-increment, "InvoiceId" int (FK), "SomeReference" varchar(50))
The "SomeReference" field holds a value that is a combination of the Id from the parent Invoice record and some random characters. eg. "145AHTL"
Before i can set the value of SomeReference I need to know the value of the Invoice Id, but this only gets populated when it is saved to the DB. I have both parent and child records in the same Linq to SQl DB Context but I only want to perform "SubmitChanges" to the parent Invoice record only, so that i can then populate the SomeReference in the child record. I dont want to have the child InvoiceItem record saved to the DB before SomeReference is set.
How can I achieve this using Linq to Sql?
I understand that linq to sql uses the "Unit of Work" idea for saving to db, but I dont understand how I can avoid unnecessarily saving records to the db when they are not ready to be saved just yet. If there is no way around this, then why do developers bother with linq to sql, as this seems like such a huge drawback?
edit: should note that this example is just something i came up with to help describe my problem.
You can not. Not this way. And this is the only way (linq dues not support sequences). Brutally speaking - you have to fix your logic. The Id of an invoice is not a refernce field. It should not ever never be the number. This is a logical field and should be handled by your logic, outside the Id.
You example can be done, but you need to forget about the SQL and the database, but think in an ORM way.
Two issues need to be addressed in your example
First inserting the master and detail at the same time
Pseudo code for how it works:
using (var dc = new datacontext())
var master = new masterentity;
master.somedata = "data";
dc.tb_master.InsertOnSumbut(master)
var detail = new detailentity
detail.tb_master = master
dc.tb_detail.InsertOnSubmit(detail)
Submitchanges()
So you assign the entities to eachother, not the keys.
Second: the SomeReference
This first part however, does not give you the somereference field, only sets the the foreign key properly.
Your somereference field contains redundant data (not necessary) so that needs to be solved.
The somereference is a string + the ID.
So you store the string part in a column in the database (and only that) and you implement a custom property somereference by using a partial class.
public partial class tb_detail
{
public string somereference
{
get
{
return _id.ToString() + _somestring;
}}}

Can WPF handle Guids from LINQ to SQL?

I stumbled on a strange problem. In my WPF (.NET 4) window I have a simple combobox (DisplayMemberPath="Name" SelectedValuePath="Id"). When I load the window I set the combobox's ItemSource property to context.Currencies.ToList() using LINQ to SQL. The Currency table in SQL is simply [Id] [uniqueidentifier] NOT NULL PRIMARY KEY, [Name] char NOT NULL. In .NET this translates to Id = System.Guid, Name = System.String.
The problem I'm having is that the call to combobox.ItemsSource = context.Currencies.ToList(); throws a FormatException (Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)).
What I can't understand is why is this error thrown?
If I leave LINQ to SQL out of the picture, define a "test" class - public class Test { public Guid Id; public string Name; }, set the comobox.ItemsSource to a List<Test> which contains some entries, then everything works.
If I do this:
combobox.ItemsSource = context.Currencies.Select(c => new { c.Id.ToString(), c.Name }).ToList()
then everything works.
I tried setting the current thread's Culture and UICulture to "en-US" beforehand as well (just in case it's a culture problem, my default culture is "et-EE"), but that didn't help either.
I looked at the generated LINQ to SQL classes from the designer, but couldn't find any properties to alter which might have helped with this error.
Am I missing something here or is this really a bug in the .NET framework?´
PS! The Currency table contains valid entries (valid Guids).
As Thomas pointed out, I had a binding on SelectedValue and it turns out the binding also contained a FallbackValue = 1. After removing the fallback property everything works. The property was scrolled out of view, so indeed it was something I missed.

Add custom field to linq to sql auto generated entity

I have a table with a varbinary(max) column for an image. I have dropped the table on the LinqToSql designer and have set "Delay load" to true, since I don't want to load the actual image data.
Is it possible to just know if the column is null or not, without getting the actual data and still only doing one query from the database?
I would also like to use the automated entity created by Linq.
Something like a new bool HasImage {get;} property would be just what I'm looking for.
The only way for Linq to SQL to "automatically" know whether or not the column has a value is to actually ask the database for it. You can extend the partial class with fields/properties, but that's not going to eliminate the lookup.
One of the things you could do is created a computed column (assuming SQL 2005+ here, otherwise you'll have to try to adapt this to your DBMS). If your table looks like this, for example:
CREATE TABLE Foo
(
FooID int NOT NULL IDENTITY(1, 1) PRIMARY KEY,
FooName varchar(50) NOT NULL,
FooImage varbinary(max) NULL
)
You would add the computed column this way:
ALTER TABLE Foo
ADD FooHasImage AS CASE
WHEN FooImage IS NULL THEN 0
ELSE 1
END
Then you can add the FooHasImage column to your Linq to SQL entity, don't delay load it, and check that property instead of explicitly checking the FooImage property.
Also, I feel obligated to point out that storing images in a database this way is sub-optimal. It may be necessary, I don't know much about your environment, but if you're using SQL Server 2008 then consider using FILESTREAM instead, as it will use the file system for cheap "offline" BLOB storage instead of stuffing the entire thing in the database.
Create a partial class
public partial class MyTableObject
{
public bool HasImage { get { return MyColumn.HasValue; } }
}
this will probably trigger a database hit, though
I would suggest adding a new column to the database "HasImage" bit that you set when an image is uploaded or deleted
don't know the actual answer to your Q, but in case you don't get an answer: how about doing the change yourself in the DB. (that is of course if you have control over the DB design).
and put the HasImage (or HasContent) column straight in the table, with a default "false" and when you add the image you make it "true" and than you can consult that column to see if you have an image or not.

Categories

Resources