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
Related
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/
I have two Entity Framework Core entities:
public class JobOrder {
public int Id { get; set; }
public string JobTitle { get; set; }
public string Status { get; set; }
...
public IEnumerable<JobOrderUser> JobOrderUsers { get; set; }
}
public class JobOrderUser {
public int AppUserId { get; set; }
public AppUser User { get; set; }
public int JobOrderId { get; set; }
public JobOrder JobOrder { get; set; }
}
The second one is a join table used for a many-to-many between the JobOrder and User tables but I don't need to drill to the User table for this.
I want to get a collection of JobOrders that have an association with a specific user. In SQL, I would write something like this:
select distinct
a.*
from
JobOrders a
join JobOrderUser b on a.JobOrderID = b.JobOrderId
where
b.AppUserId = someId
How do I do that using LINQ method syntax?
If your entities are set up correctly, and their relationships are intact, you could load the JobOrderUsers while querying for a JobOrder and then filter by a user. Something like
JobOrder.Include(t => t.JobOrderUsers).Where(t => t.JobOrderUsers.Any(x => x.User.Id == SomeId));
You can also use the below query using join and Select the required columns data in a jobOrdersDto class. For that, you have to inject the _jobOrdersRepository and _jobOrderUserRepository repositories to your service where you are calling the required method.
var result = (from jobOrders in _jobOrdersRepository.GetAll()
join jobOrderUser in _jobOrderUserRepository.GetAll() on jobOrders.JobOrderID equals jobOrderUser.JobOrderId
where
(jobOrderUser.AppUserId == someId)
select new jobOrdersDto
{
}
Your Service class:
public class YourService
{
private readonly IRepository<jobOrders> _jobOrdersRepository;
private readonly IRepository<jobOrderUser> _jobOrderUserRepository;
public YourService(
IRepository<jobOrders> jobOrdersRepository, IRepository<jobOrderUser> jobOrderUserRepository)
: base()
{
_jobOrdersRepository = jobOrdersRepository;
_jobOrderUserRepository = jobOrderUserRepository;
}
}
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!
My model is
public class SiteConfig
{
public SiteConfig()
{
}
public int IdSiteConfig { get; set; }
public string Name { get; set; }
public byte[] SiteLogo { get; set; }
public string Brands { get; set; }
public string LinkColour { get; set; }
public IEnumerable<SiteBrand> SiteBrands { get; set; }
}
and
public class SiteBrand
{
public int Id { get; set; }
public int SiteId { get; set; }
public int BrandId { get; set; }
public Brand Brand { get; set; }
public SiteConfig SiteConfig { get; set; }
}
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public IEnumerable<SiteBrand> SiteBrands { get; set; }
}
I am following Data Base first approach. Each SiteConfig record can contain one or more Brand. So Brand is saving to another table called SiteBrand.
SiteBrand contains the forign key reference to both SiteConfig(on IdSiteConfig) and Brand(BrandId).
When I am creating a SiteConfig I want to display all the available Brand as list box where user can select one or many record(may not select any brand).
But when I bind my view with the model how can I bind my list box to the list of brands and when view is posted how can I get the selected brands.
And I have to save the SiteConfig object to database with the selected Items. And this is my DB diagram.
This is my DAL which saves to db.
public SiteConfig Add(SiteConfig item)
{
var siteConfig = new Entities.SiteConfig
{
Name = item.Name,
LinkColour = item.LinkColour,
SiteBrands = (from config in item.SiteBrands
select new SiteBrand {BrandId = config.BrandId, SiteId = config.SiteId}).
ToList()
};
_dbContext.SiteConfigs.Add(siteConfig);
_dbContext.SaveChanges();
return item;
}
Can somebody advide how to bind the list box and get the selected items.
Thanks.
Add a new Property to your SiteConfig ViewModel of type string array. We will use this to get the Selected item from the Listbox when user posts this form.
public class SiteConfig
{
//Other properties here
public string[] SelectedBrands { get; set; } // new proeprty
public IEnumerable<SiteBrand> SiteBrands { get; set; }
}
In your GET action method, Get a list of SiteBrands and assign to the SiteBrands property of the SiteConfig ViewModel object
public ActionResult CreateSiteConfig()
{
var vm = new SiteConfig();
vm.SiteBrands = GetSiteBrands();
return View(vm);
}
For demo purposes, I just hard coded the method. When you implement this, you may get the Data From your Data Access layer.
public IList<SiteBrand> GetSiteBrands()
{
List<SiteBrand> brands = new List<SiteBrand>();
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 3, Name = "Nike" } });
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 4, Name = "Reebok" } });
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 5, Name = "Addidas" } });
brands.Add(new SiteBrand { Brand = new Brand { BrandId = 6, Name = "LG" } });
return brands;
}
Now in your View, which is strongly typed to SiteConfig ViewModel,
#model SiteConfig
<h2>Create Site Config</h2>
#using (Html.BeginForm())
{
#Html.ListBoxFor(s => s.SelectedBrands,
new SelectList(Model.SiteBrands, "Brand.BrandId", "Brand.Name"))
<input type="submit" value="Create" />
}
Now when user posts this form, you will get the Selected Items value in the SelectedBrands property of the ViewModel
[HttpPost]
public ActionResult CreateSiteConfig(SiteConfig model)
{
if (ModelState.IsValid)
{
string[] items = model.SelectedBrands;
//check items now
//do your further things and follow PRG pattern as needed
}
model.SiteBrands = GetBrands();
return View(model);
}
You can have a "ViewModel" that has both the site and brand model in it. Then you can bind your view to that model. This would allow you to bind any part of the view to any part of any of the underlying models.
public class siteViewModel{
public SiteConfig x;
public Brand b; //Fill this with all the available brands
}
Of course you can include any other information your view might need (reduces the need of ViewBag as well).
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.)