Workaround for PetaPoco / SQLite aggregate date bug - sqlite

Here's complete code to create a SQLite database, fill some data into a table and then try to retrieve it. If there's an aggregate function around a datetime column, PetaPoco will throw an error.
using System;
using PetaPoco;
class Program
{
static void Main(string[] args)
{
bool filenew = false;
if (!System.IO.File.Exists(#"c:\temp\database.sq3"))
filenew = true;
System.Data.SQLite.SQLiteConnection sqltc = new System.Data.SQLite.SQLiteConnection("Data Source=" + #"c:\temp\database.sq3");
sqltc.Open();
PetaPoco.Database db = new Database(sqltc);
if (filenew)
db.Execute("create table test1 (ID_CHANNEL integer primary key autoincrement, dtfld DateTime null, name string)");
test1 t = new test1();
t.name = "No Date";
db.Insert(t);
t = new test1();
t.dtfld = DateTime.Now;
t.name = "with date";
db.Insert(t);
// SUCCESS:
test1 lt1 = db.First<test1>("select dtfld from test1 where ID_Channel = 2");
// FAILURE:
test1 lt2 = db.First<test1>("select max(dtfld) as dtfld from test1 where dtfld is not null");
}
[PetaPoco.TableName("test1")]
[PetaPoco.PrimaryKey("ID_Channel")]
public class test1
{
public long ID_Channel { get; set; }
public DateTime? dtfld { get; set; }
public string name { get; set; }
}
}
Can anybody suggest a fix that still means the POCO object contains a datetime, and I can still access the max of a date?

Found a solution - switch to NPoco. The only change to above was to replace "PetaPoco" with "NPoco".

In PetaPoco.cs change the private static Func<object, object> GetConverter function. Replace the statement return Convert.ChangeType(src, dstType, null);
TypeConverter conv = TypeDescriptor.GetConverter(dstType);
return conv.ConvertFrom(src);

Related

SQLite Xamarin.forms dosn't return the saved Data

I stuck with Xamarin.Forms SQLite.
i use this NuGet package : sqlite-net-pcl
My SQLITE Tables
I want to save the Data from my Table to a Variable with this following code
SQLiteConnection myconnection = new SQLiteConnection(Constants.DatabasePath);
SQLiteCommand cmd = new SQLiteCommand(myconnection);
myconnection.CreateTable<Modul>();
var Mods = myconnection.Query<Modul>("SELECT * FROM Modul");
Mods returns with = Count=0;
But i have saved Data. Click here
My modul class:
MoulID has Primary Key on Top [Primarykey]...
public int ModulID { get; set; }
public string Modul_Name { get; set; }
I will include my existing Database from Here
with this class
public class{
public const string DatabaseFilename = "VocalDB.db";
public static string DatabasePath
{
get
{
var basePath = "D:/C#-Projets/Vocabul/Vocabul/Vocabul/DataBase/";
return Path.Combine(basePath, DatabaseFilename);
}
}
}
In your code you create the table then you execute the query... I think the table is empty after you have created it.
myconnection.CreateTable<Modul>();
var Mods = myconnection.Query<Modul>("SELECT * FROM Modul");

The parameterized query '(#role nvarchar(5),#count int)StudentProcedure #role,#count OUT' expects the parameter '#count', which was not supplied

//Student Controller
public class Student
{
[Key]
public int StudentId { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Emial { get; set; }
public string Role { get; set; }
}
//StudentConroller (Here I called Stored Procedure)
public class AccountController : Controller
{
public ApplicationDbClass applicationDbClass;
public AccountController()
{
applicationDbClass = new ApplicationDbClass();
}
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(Student student)
{
var v1 = new SqlParameter();
v1.ParameterName = "#role";
v1.SqlDbType = SqlDbType.NVarChar;
v1.Value = "Admin";
var v2 = new SqlParameter();
v2.ParameterName = "#count";
v2.SqlDbType = SqlDbType.Int;
try
{
var result = applicationDbClass.Students.SqlQuery("StudentProcedure #role,#count OUT", v1, v2).ToArray();
}
catch(Exception e)
{
var m = e.Message;
}
return RedirectToAction("Welcome", "Student");
}
}
//Stored procedure
CREATE OR ALTER PROCEDURE StudentProcedure
#role NVARCHAR(30),
#count INT OUTPUT
AS
BEGIN
SELECT #count=COUNT(dbo.Students.Role)
FROM dbo.Students
WHERE Role=#role;
END
//DbContext Class
public class ApplicationDbClass : DbContext
{
public ApplicationDbClass() : base()
{
Database.SetInitializer<ApplicationDbClass>(new DropCreateDatabaseIfModelChanges<ApplicationDbClass>());
}
public DbSet<Student> Students { get; set; }
public DbSet<LogTable> LogTables { get; set; }
}
// Here I am using code first approch to deal with database using entity framework to call the user created stored procedure. If I make some changes on stored procedure it will not refected directly. Please give me any solution to refects the changes.
You can pass parameters in this way also
SqlConnection cnn = new SqlConnection(cnnString);
SqlCommand cmd = new SqlCommand("StudentProcedure", cnn);
cmd.Connection = cnn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#role", "Admin");
cmd.Parameters.Add("#count", SqlDbType.Int);
cmd.Parameters["#count"].Direction = ParameterDirection.Output;
string Query = cmd.ExecuteNonQuery().ToString();
Here my goal is to show how to pass normal and output parameter to procedure.
There are two issues here in your code.
You should set the default value for your output parameter. Otherwise C# code will throw an exception if you do not set default value to your output parameter. So your stored procedure should look like this:
ALTER PROCEDURE StudentProcedure
#role NVARCHAR(30),
#count INT = NULL OUTPUT
AS
BEGIN
SELECT #count=COUNT(dbo.Students.Role)
FROM dbo.Students
WHERE Role=#role;
SELECT #count;
END
GO
And the second issue is you've forgot to set Direction of your output parameter:
var sqlParameter_Role = new SqlParameter("#role", "Admin");
var sqlParameter_Count = new SqlParameter();
sqlParameter_Count.ParameterName = "#count";
sqlParameter_Count.SqlDbType = SqlDbType.Int;
sqlParameter_Count.Direction = ParameterDirection.Output;
var result = db.Database
.SqlQuery<ResultForStudentProcedure>("dbo.StudentProcedure #role"
, sqlParameter_Role
, sqlParameter_Count)
.ToList();
public class ResultForStudentProcedure
{
public int Count { get; set; }
}

DateTime? to DateTime

I am stuck. I'm creating a database of authors and run to a problem. I need to save value Umrti (date of death) to database as null, but it always save that value as 01.01.0001. I tried few things and now my code looks like this:
public class AutorDetailModel
{
public int Id { get; set; }
[Required]
public string Jmeno { get; set; }
[Required]
public string Prijmeni { get; set; }
public string ProstredniJmeno { get; set; }
[DotvvmEnforceClientFormat]
public DateTime Narozeni { get; set; }
[DotvvmEnforceClientFormat]
public DateTime? Umrti { get; set; }
public string Bio { get; set; }
public string Narodnost { get; set; }
public byte Obrazek { get; set; }
}
And in service like this:
public async Task UpdateAutorAsync(AutorDetailModel autor)
{
using (var dbContext = CreateDbContext())
{
var entity = await dbContext.Autors.FirstOrDefaultAsync(s => s.Id == autor.Id);
entity.Jmeno = autor.Jmeno;
entity.Prijmeni = autor.Prijmeni;
entity.ProstredniJmeno = autor.ProstredniJmeno;
entity.Narozeni = autor.Narozeni;
entity.Umrti = autor.Umrti;
entity.Bio = autor.Bio;
entity.Narodnost = autor.Narodnost;
entity.Obrazek = autor.Obrazek;
await dbContext.SaveChangesAsync();
}
}
However, autor.Umrti still gives me this error:
Cannot implicitly convert type 'System.DateTime?' to 'System.DateTime'. An explicit conversion exists (are you missing a cast?)
I am really stuck and will appreciate any advice. Thanks
And sorry for my bad english :)
you must check Umrti is null or not
public async Task UpdateAutorAsync(AutorDetailModel autor)
{
using (var dbContext = CreateDbContext())
{
var entity = await dbContext.Autors.FirstOrDefaultAsync(s => s.Id == autor.Id);
entity.Jmeno = autor.Jmeno;
entity.Prijmeni = autor.Prijmeni;
entity.ProstredniJmeno = autor.ProstredniJmeno;
entity.Narozeni = autor.Narozeni;
if(autor.Umrti!=null)
entity.Umrti = autor.Umrti;
entity.Bio = autor.Bio;
entity.Narodnost = autor.Narodnost;
entity.Obrazek = autor.Obrazek;
await dbContext.SaveChangesAsync();
}
}
If you're using SQL Server (possibly other Database engines too) then you can't save a NULL value in a DateTime field.
You'll have to convert the NULL to a date, any date, to save it in the db. Typically SQL Server uses '1900-01-01' to represent a NULL date. In most cases that's fine as, unless you are working with historical data around the end of the 18th Century, it won't clash with your valid data. When reading from the db you can convert all dates with a value of '1900-01-01' to null in your code, and when writing to the db if the value in code is null convert it to '1900-01-01'.

AWS SDK Dynamodb query operation on secondary index with encrypted data

I am trying to use DynamodbMapper to query data using gsi.
HashMap<String, AttributeValue> eav = new HashMap<>();
eav.put(":v1", new AttributeValue().withS(employee.getDepartment()));
eav.put(":v2", new AttributeValue().withS(employee.getContactId()));
DynamoDBQueryExpression<Employee> queryExpression =
new DynamoDBQueryExpression()
.withIndexName("DepartmentContactId-index")
.withKeyConditionExpression("Department = :v1 and contactId = :v2")
.withExpressionAttributeValues(eav)
.withConsistentRead(false);
List<Employee> items =
dynamoDBMapper.query(Employee.class, queryExpression);
I am getting bad signature exception.
PS: one of the field(column) in Employee table in dynamodb is encrypted using AWSKMS. I have configured the same KMS key in dynamodb mapper but still getting the same issue. Any pointers?
Mapper class -->
package com.test.model;
import com.amazonaws.services.dynamodbv2.datamodeling.*;
importcom.amazonaws.services.dynamodbv2.datamodeling.encryption.DoNotEncrypt;
import static com.test.util.Constants.*;
#DynamoDBTable(tableName = "Employee")
public class Employee {
private String id;
private String department;
private String contactId;
private RulesData rulesData;
// Partition Key
#DynamoDBHashKey(attributeName = ID)
#DynamoDBAutoGeneratedKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#DoNotEncrypt
#DynamoDBRangeKey(attributeName = DEPARTMENT)
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
#DoNotEncrypt
#DynamoDBAttribute(attributeName = CONTACT_ID)
public String getContactId() {
return contactId;
}
public void setContactId(String contactId) {
this.contactId = contactId;
}
#DynamoDBAttribute(attributeName = DATA)
public RulesData getRulesData() {
return rulesData;
}
public void setRulesData(RulesData rulesData) {
this.rulesData = rulesData;
}
}
If you set the projection type of the global secondary index(GSI) to be other than ALL, then the signature attribute will not be in the GSI .
Thus, if you require only unencrypted fields from your query on the GSI, use a new DynamoDBMapper without an AttributeEncryptor.
If you require encrypted fields too, set the projection type of the GSI to be ALL.

I am binding dropdownlist with SQL2008 database in my WebUserControl, but my approach could use some improvement

I am doing lab. I am trying hard to bind dropdownlist with SQL2008 database in my WebUserControl. It was a piece of cake to implement when all my front and back code stood in webusercontrol, but after that I was told that this way of implementation is quite not professional. Also, I was told that I need to built a middle class with private variables and public properties:
public class UsersIntoDLL
{
public UsersIntoDLL(int userID, string userName, string userFamilyName)
{
userID = UserID;
userName = UserName;
userFamilyName = UserFamilyName;
}
public int UserID
{ get; set; }
public string UserName
{ get; set; }
public string UserFamilyName
{ get; set; }
}
Stored Procedure:
create procedure [dbo].[GetStudentsToDDL]
as
select UserID, UserName,UserFamilyName
from dbo.Users
New Method:
public List<UsersIntoDLL> GetStudents()
{
SqlConnection conn = new SqlConnection(Config.DbConnectionString);
SqlCommand cmd = new SqlCommand("GetStudentsToDDL", conn);
cmd.CommandType = CommandType.StoredProcedure;
List<UsersIntoDLL> udll = new List<UsersIntoDLL>();
try
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
//ListItem lst = new ListItem();
//udll.Text = reader["StudentName"].ToString() + " " + reader["StudentFamilyname"].ToString();
UsersIntoDLL students = new UsersIntoDLL((int)reader["UserID"], (string)reader["UserName"],(string)reader["UserFamilyName"]);
udll.Add(students);
}
reader.Close();
}
catch (Exception ex)
{
// here should be some reference to label located in webusercontrol. don't know
// how to do it
Label err = new Label();
err.Text = ex.Message;
}
finally
{
conn.Close();
}
return udll;
}
BadaBinding in back-code of webusercontrol:
CatalogAccess ca = new CatalogAccess();
ddlStudents.DataSource = ca.GetStudents();
ddlStudents.DataTextField = "UserName";
ddlStudents.DataValueField = "UserID";
ddlStudents.DataBind();
I am getting no errors and no binding. Students do not appear in my dropdownlist. Please help!!!
Ahh you weren't setting the variables in your class properly.
Use this instead:
public class UsersIntoDLL {
public UsersIntoDLL(int userID, string userName, string userFamilyName)
{
UserID = userID;
UserName = userName;
UserFamilyName = userFamilyName;
}
public int UserID
{
get;
set;
}
public string UserName
{
get;
set;
}
public string UserFamilyName
{
get;
set;
}
}
Nothing immediately jumps out but have you thought about using ObjectDataSource (linky)
p.s. Have you checked the list isn't empty?
Assuming you're running this in Visual Studio, could you set a breakpoint on the ddlStudents.DataSource = ca.GetStudents() line and make sure it is not empty?
To rule other potential issues out, change that line temporarily to:
ddlStudents.DataSource = new { UserName = "Test", UserID = "1" };
and see if at least one item shows in the drop-down.

Resources