Cannot work with more than one table. What to do to get to work with two, three or more tables?
Visual Studio >>> Xamarin-Forms
/// I think maybe this code needs to be fixed somehow.
/// this code is placed in App.cs (up)
static Data.TableTwo tabletwo;
static Data.TableOne tableone;
/// crashed
public Task<int> SaveItemAsync(TableTwo item)
{
if (item.ID != 0)
{
return tabletwo.UpdateAsync(item);
}
else
{
return tabletwo.InsertAsync(item);
}
}
/// ***I think maybe this code needs to be fixed somehow.
/// this code is placed in App.cs (down below)
public static Data.TableTwo tabletwo
{
get
{
if (datadistance == null)
{
tabletwo = new Data.TableTwo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TodoSQLite.db3"));
}
return tabletwo;
}
}
/// ***I think maybe this code needs to be fixed somehow.
/// this code is placed in App.cs (down below)
public static Data.TableOne tableone
{
get
{
if (tableone == null)
{
tableone = new Data.TableOne(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TodoSQLite.db3"));
}
return tableone;
}
}
above code works correctly. When the code above is called. Application falls.
I have two tables. With one table when the user works (saves and deletes data), then everything works. If the user starts working with another table (save data) the application crashes.
!!!application tree!!!
DataBase(folder)
TableTwo(file)
TableOne(file)
Models(folder)
TableTwo(file)
TableOne(file)
Everything was done according to the code from the article https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/databases#using-sqlite
In fact, I just copied the code a second time, and pasted into the project. - this is what I have done creating the second table and working with it (deleting insert data)
Let's assume your two tables are of types Load and Category and your database is of type MyDatabase
You might want to keep a single connection to SqlLite inside the MyDatabase class and add the methods to interact with your tables as follows:
public class MyDatabase
{
private readonly SQLiteAsyncConnection _connection;
public MyDatabase():this(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MyDatabase.db3"))
{
}
internal MyDatabase(string dbPath)
{
_connection = new SQLiteAsyncConnection(dbPath);
_connection.CreateTableAsync<Load>().Wait();
_connection.CreateTableAsync<Category>().Wait();
}
public Task<List<Load>> GetLoads() =>
_connection.Table<Load>().ToListAsync();
public Task<List<Category>> GetCategories() =>
_connection.Table<Category>().ToListAsync();
public Task<Load> GetLoad(int id) =>
_connection.Table<Load>().Where(i => i.Id == id).FirstOrDefaultAsync();
public Task<int> SaveLoad(Load item) =>
item.Id != 0 ? _connection.UpdateAsync(item) : _connection.InsertAsync(item);
public Task<int> DeleteLoad(Load item) =>
_connection.DeleteAsync(item);
}
Here is a good sample: https://github.com/xamarin/xamarin-forms-samples/blob/master/Todo/Todo/Data/TodoItemDatabase.cs, but it contains a single table 😊
Related
In app I'm bulding I used data model presented by James_D here:
Applying MVC With JavaFx
I just can find a way to bind labels text to property of object held in DataModel
Data is structured like this:
model class Student
//partial class
public class Student {
private final StringProperty displayName = new SimpleStringProperty();
public final StringProperty displayNameProperty(){
return this.displayName;
}
public Student(){
}
public final String getDisplayName() {
return this.displayNameProperty().get();
}
public final void setDisplayName(String displayName) {
this.displayNameProperty().set(displayName);
}
}
Student instaces are held by StudentDataModel class
public class StudentDataModel {
// complete student list
private final ObservableList<Student> studentList = FXCollections.observableArrayList();
private final ObjectProperty<Student> selectedStudent = new SimpleObjectProperty<>(new Student());
public final Student getSelectedStudent() {
return selectedStudent.get();
}
public final ObjectProperty<Student> selectedStudentProperty() {
return selectedStudent;
}
public final void setSelectedStudent(Student student) {
selectedStudent.set(student);
}
}
StudentList is displayed by Table View, there is change listener that sets selectedStudent like this:
public class TableViewController {
public void initModel(StudentDataModel studentDM) {
// ensure model is set once
if (this.studentDM != null) {
throw new IllegalStateException("StudentDataModel can only be initialized once");
}
this.studentDM = studentDM;
tableView.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
if (newSelection != null) {
studentDM.setSelectedStudent(newSelection);
}
});
}}
There is another controller ActionsBarController that has label to display selected student (this seems redundant, but there is option for selecting multiple objects to perform bulk operations).
StudentDataModel is initialized properly (I can see it in debuger) but below doesn't do anything:
chosenStudentLabel.textProperty().bind(studentDM.getSelectedStudent().displayNameProperty());
//this shows class name with instance number changing correctly
chosenStudentLabel.textProperty().bind(studentDM.selectedStudentProperty().asString());
I could inject ActionsBarController to TableViewController and change label text from change Listener there, but this seems counter productive with data model.
What am I doing wrong?
Your code doesn't work, because you call (and evaluate) getSelectedStudent() at the time the binding is created (i.e. when you initialize the model). As a consequence, you only bind to the displayName property of the student that is selected at that time. (If nothing is selected, you'll get a NullPointerException.) The binding will only change if that initially-selected student's display name changes; it won't change if the selection changes.
You need a binding that unbinds from the old selected student's display name, and binds to the new selected student's display name, when the selected student changes. One way to do this is:
chosenStudentLabel.textProperty().bind(new StringBinding() {
{
studentDM.selectedStudentProperty().addListener((obs, oldStudent, newStudent) -> {
if (oldStudent != null) {
unbind(oldStudent.displayNameProperty());
}
if (newStudent != null) {
bind(newStudent.displayNameProperty());
}
invalidate();
});
}
#Override
protected String computeValue() {
if (studentDM.getSelectedStudent() == null) {
return "" ;
}
return studentDM.getSelectedStudent().getDisplayName();
}
});
Note that there is also a "built-in" way to do this, but it's a bit unsatisfactory (in my opinion) for a couple of reasons. Firstly, it relies on specifying the name of the "nested property" as a String, using reflection to access it. This is undesirable because it has no way to check the property exists at compile time, it requires opening the module for access, and it is less good performance-wise. Secondly, it gives spurious warnings if one of the properties in the "chain" is null (e.g. in this case if the selected student is null, which is will be initially), even though this is a supported case according to the documentation. However, it is significantly less code:
chosenStudentLabel.textProperty().bind(
Bindings.selectString(studentDM.selectedStudentProperty(), "displayName")
);
I have a content part that provides a begin timestamp and end timestamp option. These 2 fields are used to define a period of time in which the content item should be displayed.
I now have difficulties to implement a skip approach whereas content items should not be displayed / skipped when the period of time does not span the current time.
Digging in the source code and trying to find an entry point for my approach resulted in the following content handler
public class SkipContentHandler : Orchard.ContentManagement.Handlers.ContentHandler
{
protected override void BuildDisplayShape(Orchard.ContentManagement.Handlers.BuildDisplayContext aContext)
{
if (...) // my condition to process only content shapes which need to be skipped
{
aContext.Shape = null; // return null shape to skip it
}
}
}
This works but there are several side effects
I had to alter the source code of BuildDisplayContext as the Shape is normally read only
List shape may displayed a wrong pager when it contains content items with my content part because the Count() call in ContainerPartDriver.Display() is executed before BuildDisplay()
calling the URL of a content item that is skipped results in an exception because View(null) is abigious
So, what would be the correct approach here or is there any module in existence that does the job? I couldn't find one.
This is a quite complex task. There are several steps needed to achieve a proper skipping of display items:
Create the part correctly
There are a few pitfalls here as when coming to the task of adding a part view one might utilize Orchards date time editor in connection with the DateTime properties. But this brings a heck of a lot of additional issues to the table but these don't really relate to the question.
If someone is interested in how to use Orchards date time editor then i can post this code too, but for now it would only blow up the code unnecessarly.
So here we go, the part class...
public class ValidityPart : Orchard.ContentManagement.ContentPart<ValidityPartRecord>
{
// public
public System.DateTime? ValidFromUtc
{
get { return Retrieve(r => r.ValidFromUtc); }
set { Store(r => r.ValidFromUtc, value); }
}
...
public System.DateTime? ValidTillUtc
{
get { return Retrieve(r => r.ValidTillUtc); }
set { Store(r => r.ValidTillUtc, value); }
}
...
public bool IsContentItemValid()
{
var lUtcNow = System.DateTime.UtcNow;
return (ValidFromUtc == null || ValidFromUtc.Value <= lUtcNow) && (ValidTillUtc == null || ValidTillUtc.Value >= lUtcNow);
}
...
}
...and the record class...
public class ValidityPartRecord : Orchard.ContentManagement.Records.ContentPartRecord
{
// valid from value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections
// (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue)
public virtual System.DateTime? ValidFromUtc { get; set; }
// valid from value as UTC to use Orchard convention (see CommonPart table) and to be compatible with projections
// (date/time tokens work with UTC values, see https://github.com/OrchardCMS/Orchard/issues/6963 for a related issue)
public virtual System.DateTime? ValidTillUtc { get; set; }
}
Create a customized content query class
public class MyContentQuery : Orchard.ContentManagement.DefaultContentQuery
{
// public
public ContentQuery(Orchard.ContentManagement.IContentManager aContentManager,
Orchard.Data.ITransactionManager aTransactionManager,
Orchard.Caching.ICacheManager aCacheManager,
Orchard.Caching.ISignals aSignals,
Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentTypeRecord> aContentTypeRepository,
Orchard.IWorkContextAccessor aWorkContextAccessor)
: base(aContentManager, aTransactionManager, aCacheManager, aSignals, aContentTypeRepository)
{
mWorkContextAccessor = aWorkContextAccessor;
}
protected override void BeforeExecuteQuery(NHibernate.ICriteria aContentItemVersionCriteria)
{
base.BeforeExecuteQuery(aContentItemVersionCriteria);
// note:
// this method will be called each time a query for multiple items is going to be executed (e.g. content items of a container, layers, menus),
// this gives us the chance to add a validity criteria
var lWorkContext = mWorkContextAccessor.GetContext();
// exclude admin as content items should still be displayed / accessible when invalid as validity needs to be editable
if (lWorkContext == null || !Orchard.UI.Admin.AdminFilter.IsApplied(lWorkContext.HttpContext.Request.RequestContext))
{
var lUtcNow = System.DateTime.UtcNow;
// left outer join of ValidityPartRecord table as part is optional (not present on all content types)
var ValidityPartRecordCriteria = aContentItemVersionCriteria.CreateCriteria(
"ContentItemRecord.ValidityPartRecord", // string adopted from foreach loops in Orchard.ContentManagement.DefaultContentQuery.WithQueryHints()
NHibernate.SqlCommand.JoinType.LeftOuterJoin
);
// add validity criterion
ValidityPartRecordCriteria.Add(
NHibernate.Criterion.Restrictions.And(
NHibernate.Criterion.Restrictions.Or(
NHibernate.Criterion.Restrictions.IsNull("ValidFromUtc"),
NHibernate.Criterion.Restrictions.Le("ValidFromUtc", lUtcNow)
),
NHibernate.Criterion.Restrictions.Or(
NHibernate.Criterion.Restrictions.IsNull("ValidTillUtc"),
NHibernate.Criterion.Restrictions.Ge("ValidTillUtc", lUtcNow)
)
)
);
}
}
// private
Orchard.IWorkContextAccessor mWorkContextAccessor;
}
This essentially adds a left join of the validity part fields to the SQL query (content query) and extends the WHERE statement with the validity condition.
Please note that this step is only possible with the solution described the following issue: https://github.com/OrchardCMS/Orchard/issues/6978
Register the content query class
public class ContentModule : Autofac.Module
{
protected override void Load(Autofac.ContainerBuilder aBuilder)
{
aBuilder.RegisterType<MyContentQuery>().As<Orchard.ContentManagement.IContentQuery>().InstancePerDependency();
}
}
Create a customized content manager
public class ContentManager : Orchard.ContentManagement.DefaultContentManager
{
// public
public ContentManager(
Autofac.IComponentContext aContext,
Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentTypeRecord> aContentTypeRepository,
Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentItemRecord> aContentItemRepository,
Orchard.Data.IRepository<Orchard.ContentManagement.Records.ContentItemVersionRecord> aContentItemVersionRepository,
Orchard.ContentManagement.MetaData.IContentDefinitionManager aContentDefinitionManager,
Orchard.Caching.ICacheManager aCacheManager,
System.Func<Orchard.ContentManagement.IContentManagerSession> aContentManagerSession,
System.Lazy<Orchard.ContentManagement.IContentDisplay> aContentDisplay,
System.Lazy<Orchard.Data.ITransactionManager> aTransactionManager,
System.Lazy<System.Collections.Generic.IEnumerable<Orchard.ContentManagement.Handlers.IContentHandler>> aHandlers,
System.Lazy<System.Collections.Generic.IEnumerable<Orchard.ContentManagement.IIdentityResolverSelector>> aIdentityResolverSelectors,
System.Lazy<System.Collections.Generic.IEnumerable<Orchard.Data.Providers.ISqlStatementProvider>> aSqlStatementProviders,
Orchard.Environment.Configuration.ShellSettings aShellSettings,
Orchard.Caching.ISignals aSignals,
Orchard.IWorkContextAccessor aWorkContextAccessor)
: base(aContext, aContentTypeRepository, aContentItemRepository, aContentItemVersionRepository, aContentDefinitionManager, aCacheManager, aContentManagerSession,
aContentDisplay, aTransactionManager, aHandlers, aIdentityResolverSelectors, aSqlStatementProviders, aShellSettings, aSignals)
{
mWorkContextAccessor = aWorkContextAccessor;
}
public override ContentItem Get(int aId, Orchard.ContentManagement.VersionOptions aOptions, Orchard.ContentManagement.QueryHints aHints)
{
var lResult = base.Get(aId, aOptions, aHints);
if (lResult != null)
{
// note:
// the validity check is done here (after the query has been executed!) as changing base.GetManyImplementation() to
// apply the validity critera directly to the query (like in ContentQuery) will not work due to a second attempt to retrieve the
// content item from IRepository<> (see base.GetManyImplementation(), comment "check in memory") when the query
// returns no data (and the query should not return data when the validity critera is false)
//
// http://stackoverflow.com/q/37841249/3936440
var lWorkContext = mWorkContextAccessor.GetContext();
// exclude admin as content items should still be displayed / accessible when invalid as validity needs to be editable
if (lWorkContext == null || !Orchard.UI.Admin.AdminFilter.IsApplied(lWorkContext.HttpContext.Request.RequestContext))
{
var lValidityPart = lResult.As<ValidityPart>();
if (lValidityPart != null)
{
if (lValidityPart.IsContentItemValid())
{
// content item is valid
}
else
{
// content item is not valid, return null (adopted from base.Get())
lResult = null;
}
}
}
}
return lResult;
}
// private
Orchard.IWorkContextAccessor mWorkContextAccessor;
}
Steps 2-4 are needed when having content items whereas the content type has a Container and Containable part or even content items which are processed / displayed separately. Here you normally cannot customize the content query that is executed behind the scenes.
Steps 2-4 are not needed if you use the Projection module. But again, this brings a few other issues to the table as reported in this issue: https://github.com/OrchardCMS/Orchard/issues/6979
I'm putting together a web API that needs to match an external sources XML format and was looking to rename the Data Type objects in the swagger output.
It's working fine on the members of the class but I was wondering if it was possible to override the class name as well.
Example:
[DataContract(Name="OVERRIDECLASSNAME")]
public class TestItem
{
[DataMember(Name="OVERRIDETHIS")]
public string toOverride {get; set;}
}
In the generated output I end up seeing
Model:
TestItem {
OVERRIDETHIS (string, optional)
}
I'd hope to see
OVERRIDECLASSNAME {
OVERRIDETHIS (string, optional)
}
Is this possible?
Thanks,
I had the same problem and I think I solved it now.
First of all add SchemaId in Swagger Configuration (from version 5.2.2 see https://github.com/domaindrivendev/Swashbuckle/issues/457):
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SchemaId(schemaIdStrategy);
[...]
}
Then add this method:
private static string schemaIdStrategy(Type currentClass)
{
string returnedValue = currentClass.Name;
foreach (var customAttributeData in currentClass.CustomAttributes)
{
if (customAttributeData.AttributeType.Name.ToLower() == "datacontractattribute")
{
foreach (var argument in customAttributeData.NamedArguments)
{
if (argument.MemberName.ToLower() == "name")
{
returnedValue = argument.TypedValue.Value.ToString();
}
}
}
}
return returnedValue;
}
Hope it helps.
Pretty old question, but as I was looking for a similar solution, I bumped into this.
I think the code in Vincent's answer might not work.
Here is my take on it:
private static string schemaIdStrategy(Type currentClass)
{
var dataContractAttribute = currentClass.GetCustomAttribute<DataContractAttribute>();
return dataContractAttribute != null && dataContractAttribute.Name != null ? dataContractAttribute.Name : currentClass.Name;
}
Adding to the thread as I am not able to use the answer with Swashbukle for AspNetCore.
I am doing this. However I am not totally happy as if the object is contain in another object it is showing its original name. For example if you have a result set that is Paged That result is shown incorrectly.So this is not a final answer but might work on simple use cases.
I am using a Schema Filter. And the object just have [JsonObject(Title="CustomName")] as I get the Title property for the data type.
First Define a class like this:
public class CustomNameSchema : ISchemaFilter
{
public void Apply(Schema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var objAttribute = context.SystemType.GetCustomAttribute<JsonObjectAttribute>();
if( objAttribute!= default && objAttribute?.Title?.Length > 0)
{
schema.Title = objAttribute.Title;
}
}
}
On the startup you must configure a SchemaFilter
c.SchemaFilter<CustomNameSchema>();
I am new to ASP.NET MVC and I am stuck on a point. I am working on a classified site. My situation is, I have a lot of categories in which a user can post their ads and each ad category have different View. I have created a Controller Action like
public ActionResult PostAd(string CategoryName, string SubCategoryName)
{
if(categoryName == "Vehicle" && SubCategoryName == "Cars")
{
var model = new CarAdViewModel();
// set CarAdViewModel properties...
return View("CarAdCreateView", model);
}
else if(categoryName == "Vehicle" && SubCategoryName == "Bikes")
{
var model = new BikeAdViewModel();
// set BikeAdViewModel properties...
return View("BikeAdViewModel", model);
}
else if(categoryName == "Property" && SubCategoryName == "RentHouse")
{
var model = new RentHouseAdViewModel();
// set RentHouseAdViewModel properties...
return View("RentHouseAdViewModel", model);
}
else................... so on and so on
}
My problem is I have huge number of Categories and Sub Categories almost 60+. And if I keep on coding like above for 60+ categories and subcategories, my PostAd method is going to blast and become unmanageable.
Please tell me some best practice or pattern which can bring me out of this problem.
Unfortunately, some of what you are doing cannot be avoided. There needs to be some form of model and view selection based on category.
Use a factory pattern. Create a base class:
public abstract class BaseCategory
{
public abstract string GetViewName();
public abstract Object CreateModelFromFormData();
}
For each category, create a sub-class derived from BaseCategory and implement the abstract functions.
In your action, do the following:
public ActionResult PostAd(string categoryName, string subCategoryName)
{
BaseFactory factory;
if (categoryName == "Vehicle")
{
if (subCategoryName == "Cars")
{
factory = new CarsFactory();
}
else ...
}
else ...
return View(factory.GetViewName(), factory.CreateModelFromFormData());
}
I have a couple reasons for this schema:
I am purposefully using if/else for the factory selection. Your controller is going to be created and re-created for every action call. So pre-populating a list will constantly and needlessly create objects for categories that will not be selected. A simple if/else will be more efficient. If you want to prevent the if/else, you can put your factories in a Dictionary and select based on the categories, but that would be a lot of needless constructor actions.
I made the CreateModelFromFormData a function because I assume you'll need to copy data from the posted form data. This may require passing in data, but I left the function parameterless.
I used base/derived classes because the copying of the form data will probably need to be custom from the model being created and the form data being posted. Also, saving to persistent storage (file or database) may be category-specific as well.
It would be one of some possible solutions
public class PostAdData
{
public string CategoryName;
public string SubCategoryName;
public string ViewName;
public Type Model;
}
public class PostController : Controller
{
private readonly List<PostAdData> _theData;
public HomeController()
{
_theData = InitializeData();
}
public ActionResult PostAd(string categoryName, string subCategoryName)
{
var data = _theData.FirstOrDefault(c => c.CategoryName == categoryName && c.SubCategoryName == subCategoryName);
if (data != null)
{
var model = Activator.CreateInstance(data.Model);
return View(data.ViewName, model);
}
return View("Error");
}
[NonAction]
public List<PostAdData> InitializeData()
{
var result = new List<PostAdData>
{
new PostAdData
{
CategoryName = "Vehicle",
SubCategoryName = "Cars",
ViewName = "CarAdCreateView",
Model = typeof (CarAdViewModel)
}
};
return result;
}
}
You should make this data driven. You create a lookup table that has a compound primary key of category and subcategory. Then it has a table with View in it. Then you simply ad rows for each category/subcategory/view combination.
If you absolutely don't want a database, then you can use a simple hashset or dictionary.
var views = new Dictionary<Tuple<string,string>,string>();
views.Add(new Tuple<string,string>("Vehicle", "Cars"), "CarAdCreateView");
Then in your PostAd you just lookup the correct view.
What a beautiful solution on www.asp.net to my question, here is the link : http://forums.asp.net/t/1923868.aspx/1?ASP+NET+MVC+Conditional+ViewModel+Abstraction
Edit:
My code is :
public class AdsController : Controller
{
private readonly IAdService _adService;
public AdsController(IAdService adService)
{
_adService = adService;
}
public ActionResult PostAd(string Category, string SubCategory)
{
//Here I will call
var strategy = GetStrategy(CategoryName, SubCategoryName);
strategy.FillModel(_adService );
return View(strategy.ViewName, strategy.Model);
}
}
I have code like this:
//Fields
Product _prod, _existingProd;
void Test()
{
_prod = MakeAndPopulateSomeRandomProduct();
_existingProd = GetProdFromDb(1);
Mapper.CreateMap()
.AfterMap((s, d) =>
{
Console.WriteLine(d==_existingProd); //Why does this print false?
//Customize other properties on destination object
});
Mapper.Map(_prod, _existingProd);
}
When I call Test(), false is printed but I expected true. In my scenario, it is important to be able to access the original destination object via the AfterMap argument. I only included the fields to demonstrate the problem but in my real code, I don't have direct access to them. How can I access the object instances passed in to Map() when customizing the mapping?
The following example works. Probably you are using some type converter which creates new instance... Also please provide all mapping configurations to better understand the problem.
[TestFixture]
public class AfterMap_Test
{
//Fields
private Product _prod, _existingProd;
[Test]
public void Test()
{
Mapper.CreateMap<Product, Product>()
.AfterMap((s, d) =>
{
Trace.WriteLine(d == _existingProd); //Why does this print false?
//Customize other properties on destination object
});
_existingProd = new Product {P1 = "Destination"};
_prod = new Product {P1 = "Source"};
Mapper.Map(_prod, _existingProd);
}
}
internal class Product
{
public string P1 { get; set; }
}