How to get single row from SQLite database in Windows Store apps? - sql

If I want single primitive value like int, string, float etc I can do like this.
using (var db = new SQLiteConnection(DbPath))
{
double i = db.CreateCommand("select salary from PersonMaster where personId = ?", 9).ExecuteScalar<double>();
}
If I try to return whole object of person master i.e. single row the below code returns null
using (var db = new SQLiteConnection(DbPath))
{
PersonMaster objPersonMaster = db.CreateCommand("select * from PersonMaster where personId = ?", 9).ExecuteScalar<PersonMaster>();
}
I compulsory have to use this
using (var db = new SQLiteConnection(DbPath))
{
List<PersonMaster> lstPersonMaster = db.Query<PersonMaster>("select * from PersonMaster where personId = ?", 9);
PersonMaster objPersonMaster = lstPersonMaster.First();
}
Is there any way to get single row as object, rather than dealing with List<T>

I am assuming you are using SQLite-Net. If that is the case you can use the Find method. Find gets an object using its primary key.
The personId field needs the PrimaryKey attribute as follows:
public class PersonMaster
{
[PrimaryKey]
public int personId { get; set; }
public string name { get; set; }
public decimal salary { get; set; }
}
Then you can use Find like so:
// get person 9
PersonMaster person9 = db.Find<PersonMaster>(9);

You can either use "TOP(1) yourquery" or "yourquery LIMIT 1"

if you just want to get rid of the list step, you can do it directly:
PersonMaster objPersonMaster = db.Query<PersonMaster>("select * from PersonMaster where personId = ?", 9).First();
Of course you have to deal with a possible exception in case nothing is returned, but you should do this also with the list approach anyway.

Related

Looping through Dapper.Net query results without the use of models

I am still new to C# and I am struggling to find a solution to my problem. My SQL dapper query returns a table (based on my understanding though it is not really a table if it is IEnumerable unlike what I am use to working with ADO and recordsets) with three columns col1, col2, and col3 and has multiple rows. I need to loop through this query result for each row and test the values (ie, a foreach loop where I check row(0).field1=5, row(1).field1 = 5 for each row, etc) do what I need to do. This seems so basic but I all the dapper tutorials I see do not show examples for this and if they do they seem to utilize class objects rather than accessing the results directly (if thats even possible or do you have to map the results to a model?) My code is as follows:
String query = "exec dbo.storeProcedure #jsonData, #mainDocJSON, #supportingDocsJSON";
IEnumerable queryResult;
using (var connection = new SqlConnection(connectionString))
{
queryResult = connection.Query(query, new { jsonData = jsonData, mainDocJSON = mainDocJSON, supportingDocsJSON = supportingDocsJSON });
}
I also end up returning IEnumerable results from the controller this code resides in so I send it back to the user in JSON using the following.
return Ok(queryResult);
connection.Query return a IEnumerable, why dont we create a class to map the set from ? Dapper is a micro-ORM, but still... ORM.
For ex: Your table return 3 column Id, Name, CreatedDate.
// declare a class to map the result first
public class ResultHolderDto
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedDate { get; set; }
}
// query somewhere
// This will return IEnumerable<ResultHolderDto>, feel free to play around as normal
var queryResult = await connection.QueryAsync<ResultHolderDto>(query, new { jsonData = jsonData, mainDocJSON = mainDocJSON, supportingDocsJSON = supportingDocsJSON });
foreach(var item in queryResult)
{
var col1Value = queryResult.Id;
var col2Value = queryResult.Name;
var col3Value = queryResult.CreatedDate;
// Then do something with col1Value, col2Value, col3Value...
}

ASP.NET Web API - SQL - Retrieving Information

I am having some issues with retrieving information from sql database using ASP.net Web API.
I have tried to use forms, which worked great (using gridview) but when I try to do it using a separate class dedicated to store my specific table information I get this error:
"Index was out of range. Must be non-negative and less than the size of the collection."
This is the code:
public ActionResult Details()
{
List<Employee> employeeList = new List<Employee>();
string CS = ConfigurationManager.ConnectionStrings["EmployeeContext"].ConnectionString;
using (var myConn = new SqlConnection(CS))
{
SqlCommand cmd = new SqlCommand("select * from tblEmployee", myConn);
myConn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
int i = 0;
employeeList[i].PersonID = Convert.ToInt32(rdr["PersonID"]);
employeeList[i].Name = rdr["Name"].ToString();
employeeList[i].Gender = rdr["Gender"].ToString();
employeeList[i].City = rdr["City"].ToString();
employeeList[i].DepartmentID = Convert.ToInt32(rdr["DepartmentID"]);
i++;
}
return View(employeeList);
}
}
This is the Employee class:
[Table("tblEmployee")]
public class Employee
{
public int PersonID { get; set; }
public string Name { get; set; }
public string Gender { get; set; }
public string City { get; set; }
public int DepartmentID { get; set; }
}
}
I get this error on any of the retrieving information lines.
The table has 5 columns: PersonID(int PK), Name(nvarchar), Gender(nvarchar), City(nvarchar), DepartmentID(int).
I checked many times the columns names to make sure I didn't got those wrong and I double checked the connection string which is also fine (the same code works with gridview using forms API).
Hope someone can help me with this. I didn't find any specific information on that and I guess it's should be easy and I'm doing something wrong here.
You are trying to populate a List<> object by using an index. To populate a List<> you need to use .Add(). You need to change your code from this:
int i = 0;
employeeList[i].PersonID = Convert.ToInt32(rdr["PersonID"]);
employeeList[i].Name = rdr["Name"].ToString();
employeeList[i].Gender = rdr["Gender"].ToString();
employeeList[i].City = rdr["City"].ToString();
employeeList[i].DepartmentID = Convert.ToInt32(rdr["DepartmentID"]);
i++;
To this:
Employee emp = new Employee();
emp.PersonID = Convert.ToInt32(rdr["PersonID"]);
emp.Name = rdr["Name"].ToString();
emp.Gender = rdr["Gender"].ToString();
emp.City = rdr["City"].ToString();
emp.DepartmentID = Convert.ToInt32(rdr["DepartmentID"]);
employeeList.Add(emp);
When adding a new item to a list, you should use .Add(). Here's one option:
while (rdr.Read())
{
employeeList.Add(new Employee {
PersonID = Convert.ToInt32(rdr["PersonID"]),
Name = rdr["Name"].ToString(),
Gender = rdr["Gender"].ToString(),
City = rdr["City"].ToString(),
DepartmentID = Convert.ToInt32(rdr["DepartmentID"])
});
}
You could then access individual items in the list with their index or by using foreach.

not able to create constructor of model class and getting object reference not set to instance of object error

this is my Model:
public class UserDetails
{
public string UserName { get; set; }
public virtual Category Category { get; set; }
}
this is my query to fetch user details along with category:
var data = (from temp in context.UserDetails.Include("Category") select temp).OrderBy(c => c.UserId);
this is how i am accessing on controller:
List<UserDetails> staffDetails = staffBal.fetchStaffDetails();
var categoryModel = new CategoryModel();
Data = staffDetails.Select(x =>
{
var userDetailModel = new UserDetailsModel();
userDetailModel.UserId = x.UserId;
userDetailModel.FName = x.FName;
categoryModel.CategoryName = x.Category.Name;//i am getting error on this line.object reference not set to instance of object
can anybody tell me what is the solution???
You say in your comment: for some records it is coming null for some records it is not null meaning that x.Category is null. Therefore, any attempt to access x.Category.Name will fail. Change the line to this:
categoryModel.CategoryName = x.Category == null ? "" : x.Category.Name;

ServiceStack.ORMLite: Custom query to custom Poco with Sql.In selections?

Background
I'm attempting to use ServiceStack.OrmLite to grab some values (so I can cache them to run some processing against them).
I need to grab a combination of three values, and I have a custom SQL statement that will yield them (does the joins, etc.)
Because this will be a large list of combinations, I'd like to pass in some lists of values and use Sql.In to filter to only the results that have those values.
Specifics
I need to check whether an invoice is unique to a firm and another value (called ClaimLawsuitID here).
so have my poco:
public class FirmIDClaimLawsuitIDInvoiceNumberCombination
{
public string FirmID { get; set; }
public string ClaimLawsuitID { get; set; }
public string InvoiceNumber { get; set; }
}
and I have my SQL statement:
select tblDefenseInvoice.FirmID, tblDefInvClaimantDetail.ClaimLawsuitID, tblDefInvClaimantDetail.invoiceNumber
from tblDefenseInvoice
inner join tblDefInvClaimantDetail
on(tblDefenseInvoice.DefenseInvoiceID = tblDefInvClaimantDetail.DefenseInvoiceID)
I would like to run the following:
public List<FirmIDClaimLawsuitIDInvoiceNumberCombination> GetFirmIDClaimLawsuitIDInvoiceNumberCombinationsForExistingItems(IEnumerable<int> firmIds, IEnumerable<long> claimLawsuitIDs, IEnumerable<string> invoiceNumbers)
{
var sql = #"select tblDefenseInvoice.FirmID, tblDefInvClaimantDetail.ClaimLawsuitID, tblDefInvClaimantDetail.invoiceNumber
from tblDefenseInvoice
inner join tblDefInvClaimantDetail
on(tblDefenseInvoice.DefenseInvoiceID = tblDefInvClaimantDetail.DefenseInvoiceID)";
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<tblClaimLawsuit>();
var firmFilter = PredicateBuilder.True<tblDefenseInvoice>();
var claimLawsuitFilter = PredicateBuilder.True<tblDefInvClaimantDetail>();
var invoiceNumberFilter = PredicateBuilder.True<tblDefInvClaimantDetail>();
firmFilter = x => Sql.In(x.FirmID, firmIds);
claimLawsuitFilter = x => Sql.In(x.ClaimLawsuitID, claimLawsuitIDs);
invoiceNumberFilter = x => Sql.In(x.InvoiceNumber, invoiceNumbers);
ev.Select(sql);
ev.Where(firmFilter);
ev.Where(claimLawsuitFilter);
ev.Where(invoiceNumberFilter);
return dal.DB.Select<FirmIDClaimLawsuitIDInvoiceNumberCombination>(ev.ToSelectStatement());
}
Question
Is this possible to achieve this way?
Is there some other way of achieving this within ServiceStack's OrmLite that is cleaner and I'm unaware of?
Since I was selecting to a POCO, I simply needed to add the filters based on that POCO.
The following worked just fine:
public List<FirmIDClaimLawsuitIDInvoiceNumberCombination>
GetFirmIDClaimLawsuitIDInvoiceNumberCombinationsForExistingItems(
IEnumerable<long> firmIds,
IEnumerable<long> claimLawsuitIDs)
{
var sql = #"select tblDefenseInvoice.FirmID, tblDefInvClaimantDetail.ClaimLawsuitID, tblDefInvClaimantDetail.invoiceNumber
from tblDefenseInvoice
inner join tblDefInvClaimantDetail
on(tblDefenseInvoice.DefenseInvoiceID = tblDefInvClaimantDetail.DefenseInvoiceID)";
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<FirmIDClaimLawsuitIDInvoiceNumberCombination>();
var firmFilter = PredicateBuilder.True<FirmIDClaimLawsuitIDInvoiceNumberCombination>();
var claimLawsuitFilter = PredicateBuilder.True<FirmIDClaimLawsuitIDInvoiceNumberCombination>();
firmFilter = x => Sql.In(x.FirmID, firmIds);
claimLawsuitFilter = x => Sql.In(x.ClaimLawsuitID, claimLawsuitIDs);
ev.Select(sql);
ev.Where(firmFilter);
ev.Where(claimLawsuitFilter);
return dal.DB.Select<FirmIDClaimLawsuitIDInvoiceNumberCombination>(ev.ToSelectStatement());
}

ROW_NUMBER() and nhibernate - finding an item's page

given a query in the form of an ICriteria object, I would like to use NHibernate (by means of a projection?) to find an element's order,
in a manner equivalent to using
SELECT ROW_NUMBER() OVER (...)
to find a specific item's index in the query.
(I need this for a "jump to page" functionality in paging)
any suggestions?
NOTE: I don't want to go to a page given it's number yet - I know how to do that - I want to get the item's INDEX so I can divide it by page size and get the page index.
After looking at the sources for NHibernate, I'm fairly sure that there exists no such functionality.
I wouldn't mind, however, for someone to prove me wrong.
In my specific setting, I did solve this problem by writing a method that takes a couple of lambdas (representing the key column, and an optional column to filter by - all properties of a specific domain entity). This method then builds the sql and calls session.CreateSQLQuery(...).UniqueResult(); I'm not claiming that this is a general purpose solution.
To avoid the use of magic strings, I borrowed a copy of PropertyHelper<T> from this answer.
Here's the code:
public abstract class RepositoryBase<T> where T : DomainEntityBase
{
public long GetIndexOf<TUnique, TWhere>(T entity, Expression<Func<T, TUnique>> uniqueSelector, Expression<Func<T, TWhere>> whereSelector, TWhere whereValue) where TWhere : DomainEntityBase
{
if (entity == null || entity.Id == Guid.Empty)
{
return -1;
}
var entityType = typeof(T).Name;
var keyField = PropertyHelper<T>.GetProperty(uniqueSelector).Name;
var keyValue = uniqueSelector.Compile()(entity);
var innerWhere = string.Empty;
if (whereSelector != null)
{
// Builds a column name that adheres to our naming conventions!
var filterField = PropertyHelper<T>.GetProperty(whereSelector).Name + "Id";
if (whereValue == null)
{
innerWhere = string.Format(" where [{0}] is null", filterField);
}
else
{
innerWhere = string.Format(" where [{0}] = :filterValue", filterField);
}
}
var innerQuery = string.Format("(select [{0}], row_number() over (order by {0}) as RowNum from [{1}]{2}) X", keyField, entityType, innerWhere);
var outerQuery = string.Format("select RowNum from {0} where {1} = :keyValue", innerQuery, keyField);
var query = _session
.CreateSQLQuery(outerQuery)
.SetParameter("keyValue", keyValue);
if (whereValue != null)
{
query = query.SetParameter("filterValue", whereValue.Id);
}
var sqlRowNumber = query.UniqueResult<long>();
// The row_number() function is one-based. Our index should be zero-based.
sqlRowNumber -= 1;
return sqlRowNumber;
}
public long GetIndexOf<TUnique>(T entity, Expression<Func<T, TUnique>> uniqueSelector)
{
return GetIndexOf(entity, uniqueSelector, null, (DomainEntityBase)null);
}
public long GetIndexOf<TUnique, TWhere>(T entity, Expression<Func<T, TUnique>> uniqueSelector, Expression<Func<T, TWhere>> whereSelector) where TWhere : DomainEntityBase
{
return GetIndexOf(entity, uniqueSelector, whereSelector, whereSelector.Compile()(entity));
}
}
public abstract class DomainEntityBase
{
public virtual Guid Id { get; protected set; }
}
And you use it like so:
...
public class Book : DomainEntityBase
{
public virtual string Title { get; set; }
public virtual Category Category { get; set; }
...
}
public class Category : DomainEntityBase { ... }
public class BookRepository : RepositoryBase<Book> { ... }
...
var repository = new BookRepository();
var book = ... a persisted book ...
// Get the index of the book, sorted by title.
var index = repository.GetIndexOf(book, b => b.Title);
// Get the index of the book, sorted by title and filtered by that book's category.
var indexInCategory = repository.GetIndexOf(book, b => b.Title, b => b.Category);
As I said, this works for me. I'll definitely tweak it as I move forward. YMMV.
Now, if the OP has solved this himself, then I would love to see his solution! :-)
ICriteria has this 2 functions:
SetFirstResult()
and
SetMaxResults()
which transform your SQL statement into using ROW_NUMBER (in sql server) or limit in MySql.
So if you want 25 records on the third page you could use:
.SetFirstResult(2*25)
.SetMaxResults(25)
After trying to find an NHibernate based solution for this myself, I ultimately just added a column to the view I happened to be using:
CREATE VIEW vw_paged AS
SELECT ROW_NUMBER() OVER (ORDER BY Id) AS [Row], p.column1, p.column2
FROM paged_table p
This doesn't really help if you need complex sorting options, but it does work for simple cases.
A Criteria query, of course, would look something like this:
public static IList<Paged> GetRange(string search, int rows)
{
var match = DbSession.Current.CreateCriteria<Job>()
.Add(Restrictions.Like("Id", search + '%'))
.AddOrder(Order.Asc("Id"))
.SetMaxResults(1)
.UniqueResult<Paged>();
if (match == null)
return new List<Paged>();
if (rows == 1)
return new List<Paged> {match};
return DbSession.Current.CreateCriteria<Paged>()
.Add(Restrictions.Like("Id", search + '%'))
.Add(Restrictions.Ge("Row", match.Row))
.AddOrder(Order.Asc("Id"))
.SetMaxResults(rows)
.List<Paged>();
}