Windows Phone SQL Server CE - Retrieve underlying database schema for upgrade - linq

Windows Phone 7.1 supports SQL Server CE and LINQ to SQL, as well as upgrading the database via DatabaseSchemaUpdater.
On other platforms I would read the database schema tables (e.g. sys.objects) to view the current schema and work out what tables/columns need to be upgraded.
Given that no direct SQL access is allowed on Windows Phone, how can retrieve the current database schema?

SQL Server CE still includes the INFORMATION_SCHEMA.TABLES and INFORMATION_SCHEMA.COLUMNS tables, but it is a little tricky to access them as no direct SQL access is allowed.
However, you can create a DataContext which maps to these tables:
public class SchemaContext : DataContext
{
public SchemaContext()
: base("Data Source=isostore:/Database.sdf")
{
if (!this.DatabaseExists())
{
throw new InvalidOperationException("Cannot use the SchemaContext on a database which doesn't exist");
}
}
public Table<Table> Tables;
public Table<Column> Columns;
[Table(Name = "INFORMATION_SCHEMA.Columns")]
public class Column
{
[Column(Name = "TABLE_NAME")]
public string TableName { get; set; }
[Column(Name = "COLUMN_NAME")]
public string Name { get; set; }
[Column(Name = "DATA_TYPE")]
public string DataType { get; set; }
[Column(Name = "ORDINAL_POSITION")]
public int OrdinalPosition { get; set; }
[Column(Name = "IS_NULLABLE")]
public string IsNullableString { get; set; }
public bool IsNullable
{
get { return this.IsNullableString == "YES"; }
set { this.IsNullableString = value ? "YES" : "NO"; }
}
}
[Table(Name = "INFORMATION_SCHEMA.Tables")]
public class Table
{
[Column(Name = "TABLE_NAME")]
public string Name { get; set; }
[Column(Name = "TABLE_TYPE")]
public string Type { get; set; }
}
}
You can then read the schema with the following code:
using (var schemaContext = new SchemaContext())
{
foreach (var table in schemaContext.Tables)
{
}
}
It's important to create a separate context for these tables, as otherwise the DataContext.CreateDatabase call will attempt to create these schema tables, which will fail.

There is a Walkthrough for Updating a Local Database Application for Windows Phone on MSDN which advocates using the DatabaseSchemaVersion on the DatabaseSchemaUpdater - i.e:
// Set the new database version.
DatabaseSchemaUpdater dbUpdater = db.CreateDatabaseSchemaUpdater();
dbUpdater.DatabaseSchemaVersion = APP_VERSION;
dbUpdater.Execute();
You can query the version and add the bits that you add in each release, without having to worry about the current schema (after all, it'll be a known configuration as long as you remember to keep the version numbers updated correctly.)

Related

How to dynamically create controls in .NET MAUI (or Xamarin)?

I need to visualize a database schema of any database. For the sake of simplicity, doing it without links between tables. Now i've fot a column class with name and datatype, a table class with name and list of columns and a DBSchema class with a list of tables. The tables should also be indented in a single row for simplicity. How to visualize the schema if tables quantity and content is unknown?
I've tried using UraniumUI DataGrid to visualize a single table, but couldn't figure out what can I do next as I'm new to MAUI or Xamarin. Here are my classes and method to get the schema:
public class Column
{
public string ColumnName { get; set; }
public string DataType { get; set; }
public bool IsPrimaryKey { get; set; }
}
public class Table
{
public string TableName { get; set; }
public List<Column> Columns { get; set; }
}
public class DBSchema
{
public List<Table> Tables { get; set; }
public void AddTable(Table table)
{
Tables.Add(table);
}
}
public static DBSchema GetDBSchema(string connectionString)
{
DBSchema schema = new DBSchema();
var connection = new SqlConnection(connectionString);
connection.Open();
DataTable tablesScheme = connection.GetSchema("Tables");
foreach (DataRow table in tablesScheme.Rows)
{
string tableName = table["TABLE_NAME"].ToString();
DataTable columnsScheme = connection.GetSchema("Columns", new string[] { null, null, tableName });
List<Column> columns = new List<Column>();
foreach (DataRow column in columnsScheme.Rows)
{
columns.Add(new Column(column["COLUMN_NAME"].ToString(), column["DATA_TYPE"].ToString()));
}
schema.AddTable(new Table(tableName, columns));
}
connection.Close();
return schema;
}
In general you can use nested collection view with custom data templates
<CollectionView ItemsSource="{Binding Tables}" />
Q is far too abstract for detailed answer.
https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/collectionview/?view=net-maui-7.0

SQlite Update Statement in xamarin forms

I have an SQlite table with 4 Columns in Xamarin app.
I've already inserted 3 columns and now i need an update statement to Update 4th column with some values using for loop.
(OR)
Please suggest any better/other method to do the same.
Do you want to update the record in the sqlite DB?
If so you can use this model to update the record in the DB.prijem.BCode is PrimaryKey, we set the type of PrimaryKey is int and AutoIncrement, So, if the model's PrimaryKey is not equal zero, this record stored in the DB, we can update this record by the Model.
readonly SQLiteAsyncConnection _database;
public PrijemDatabase(string dbPath)
{
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Prijem>().Wait();
}
public Task<int> SavePrijemAsync(Prijem prijem)
{
if (prijem.BCode != 0)
{
return _database.UpdateAsync(prijem);
}
else
{
return _database.InsertAsync(prijem);
}
}
Here is my model.
public class Prijem
{
[PrimaryKey, AutoIncrement, Unique]
public int BCode { get; set; }
public string Name { get; set; }
public string FirmName { get; set; }
public string ItemCode { get; set; }
public string Count { get; set; }
}
Here is link about how to execute CRUD, you can refer to it.
https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows
Here is a demo about it.
https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/getstarted-notes-database/

Using identity with custom user object

I have been trying to get this for a week now. I have read several articles on how to do it. Nevertheless I think it should not be as complicated as everybody states, running migrations/overriding and making your own implementation of userStore(thats why I'm trying to use identity), etc. Following this documentation i was able to create an identity user "ASP NET identity From empty project"
The table AspNetUsers is being populated ok, but what i would like to do is to add some more columns to this table. Here is what i have tried but keeps throwing me error.
string value = System.Configuration.ConfigurationManager.AppSettings["ConnectionString"];
var db = new IdentityDbContext(value);
var userStore = new UserStore<UsuarioTest>(db);
var manager = new UserManager<UsuarioTest>(userStore);
var user = new IdentityUser { UserName = usuario.Nombre };
var us = new UsuarioTest
{
Nombre = usuario.Nombre,
Email = usuario.Email,
UserName = usuario.Nombre,
TelefonoCelular = usuario.TelefonoCelular,
Password = usuario.Password
};
IdentityResult result = manager.Create(us, usuario.Password);
As you can see I replaced IdentityUser by UsuarioTest but this does not work properly. If I leave the IdentityUser and complete this object evrything works fine.
Finally here is my implementation for usuarioTest
public class UsuarioTest : IdentityUser
{
public DateTime CreateDate { get; set; }
public virtual string Nombre { get; set; }
public virtual string Email { get; set; }
public virtual string Password { get; set; }
public virtual string TelefonoCelular { get; set; }
public string Id { get; }
//public string UserName { get; set; }
public UsuarioTest()
{
Id = Guid.NewGuid().ToString();
}
}
I hope this description is good enough for you guys guide me to a solution.
PS:I have already tried searching applicationUser and modify this class but this is from an old version of identity. I am currently using Identity core 4.0

Linq trowing Exceptions

I create a project where I use EF with LINQ and Model first. So, based on my edmx I created my Database and also my classes.
So I got some problems. I created a Click to test if my code is working.
protected void btnSearch_Click(object sender, EventArgs e)
{
ZUser Zusr = new ZUser();
List<ZUser> lst = Zusr.ListAll();
// Zusr.Id = 1;
string test = "";
foreach (ZUser item in lst)
{
test = item.Name;
}
lblName.Text = test;
}
So in my ZUser Class (Controller) I did the following code:
[Serializable]
public class ZUser : User
{
String connString = ConfigurationManager.ConnectionStrings["ConnectionString"].ToString();
public List<ZUser> ListAll()
{
List<ZUser> lstUser = new List<ZUser>();
using (DataContext db = new DataContext(connString))
{
Table<User> Users = db.GetTable<User>();
var query =
from usr in Users
where usr.Name == "Test"
select usr;
foreach (ZUser usr in query)
lstUser.Add(usr);
}
return lstUser;
}
}
And my Model (Class generated by my edmx)
namespace System.Model
{
//[Table]
public partial class User
{
public int Codigo { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public DateTime Created { get; set; }
public DateTime LastLogin { get; set; }
}
}
Problems
If I don't let the [Table] in my Model class (I added that) I got this error. I'm not sure if this is the right way to correct it.
The type '{0}' is not mapped as a Table.
After "fixing" the problem from above. I got this new one in my foreach (ZUser usr in query).
The member '{0}.{1}' has no supported translation to SQL.
I don't know how to fix or create a workaround this one.
Amazing, this feature of linq!
Really intresting!
After some searches on msdn and test it in application,
maybe you miss the Column attribute over all single class members:
[Column(CanBeNull = false, DbType = "int")]
And maybe you must uncomment the Table attribute on top of User declaration
Hope this help!

Eager loading with Linq query with restriction on details

How can I write a query with the build-in linq provider of NHibernate including eager loading and restrictions on the details? For example
public class Library
{
public Library()
{
Books = new List<Book>();
}
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Book> Books { get; protected internal set; }
}
public class Book
{
public Book()
{
Pages = new List<Page>();
}
public virtual int Id { get; set; }
public virtual Library Library { get; set; }
public virtual string Title { get; set; }
}
the following query shows what I need but does not load eagerly
var query = from master in session.Query<Library>()
from detail in master.Books
where detail.Title == detailValue
select master;
The following query does not work ...
var query = from master in session.Query<Library>()
// not allowed - causes Runtime error
.FetchMany(m => m.Details.Where(d => d.Value == detailValue))
select master;
Thanks a lot in advance.
Carsten
You may want to consider using queryOver here instead:-
Book book = null;
var query =
Session.QueryOver<Library>()
.Fetch(f => f.Books).Eager
.Left.JoinAlias(f => f.Books, () => book)
.Where(() => actor.book == detailValue);
I may be wrong but I don't think the NH LINQ provider can support this at the moment.
Also note the .left this is important, see this blog post for reasons why

Resources