我是SQL的新手,我在将一些对象映射到一起时遇到了一些麻烦。我有一个Account对象和一个User对象。
帐户对象使用 import UIKit
import Firebase
class UsersTableViewController: UITableViewController {
var user = [User]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getusers() {
let userID = Auth.auth().currentUser?.uid
let rootRef = Database.database().reference()
let query = rootRef.child("users").queryOrdered(byChild: "fullname")
query.observe(.value) { (snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
if let value = child.value as? NSDictionary {
let userToShow = User()
let fullname = value["fullname"] as? String ?? "Name not found"
let uid = value["uid"] as? String ?? "uid not found"
userToShow.fullname = fullname
userToShow.userID = uid
self.user.append(userToShow)
DispatchQueue.main.async { self.tableView.reloadData() }
}
}
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return user.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "userCell", for: indexPath) as! TableViewCell
cell.nameLabel.text = self.user[indexPath.row].fullname
cell.userID = self.user[indexPath.row].userID
cell.userImage.downloadImage(from: self.user[indexPath.row].imagePath!)
return cell
}
}
extension UIImageView {
@objc func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}}
作为主键。用户对象使用Email
作为主键。
我希望AccountModel中的Username
字段充当用户模型的外键,但它似乎不起作用。用户对象Username
正在设置为Username
字段
Email
答案 0 :(得分:1)
在最后评论后添加
在我看来,您希望在用户和帐户之间配置一对一关系:每个用户只有一个帐户,每个帐户只有一个用户拥有。没有帐户的用户,没有没有用户的帐户。
通常情况下,使用Composition最好配置一对一:每个用户只有一个帐户。结果是用户和他的帐户在一个表中,从而加快了查询速度。此外,更容易确保没有没有帐户的用户或没有用户的帐户。更改给定用户的帐户数据也会更容易。
在实体框架中,您可以这样做:
class Account
{
public string Email {get; set;}
public string Password {get; set;} // by the way: very unsave, prone to be hacked
...
}
class User
{
public string Name {get; set;}
public Account Account {get; set;}
...
}
效果将是帐户和用户将在一个表中。
要使用具有给定名称的用户的某些帐户属性获取某些用户属性,请执行以下操作:
var result = myDbContext.Users
.Where(user => user.Name = ...)
.Select(user => new
{ // get only the properties you plan to use:
Name = user.Name,
...
// only if you also need some account properties:
Account = new
{
Email = user.Account.Email,
Password = user.Account.Password,
...
},
});
可能你没有计划真正的一对一,但是a one-to-zero-or-one relation,允许某些用户还没有帐户,或者某些帐户没有用户。这需要两个表:
class User
{
...
// every user has zero or one Account:
public virtual Account Account {get; set;}
}
class Account
{
...
// every Account belongs to zero or one User
public virtual User User {get; set;}
}
查询将类似于我上面描述的查询,除了您需要检查User.Account是否为空
最后:将电子邮件和姓名用作主键是非常不明智的
您确定每个用户都有唯一的名称吗?如果用户更改了他的名称(例如因为其中存在输入错误),那么它将是另一个用户吗?
永远不要使用可能会更改为主键的项目。如果让数据库决定主键的值,则效率最高:
class User
{
public int Id {get; set;}
...
}
class Account
{
public int Id {get; set;}
...
}
因为我跟着the Entity Framework conventions,这足以让实体框架理解Id是主键,由数据库填充。不需要属性,也不需要流畅的API。如果遵循命名约定,实体框架也足够聪明地检测外键:
一对多:假设用户拥有零个或多个帐户,每个帐户仅由一个用户拥有:
class User
{
public int Id {get; set;}
// every user has zero or more Accounts:
public virtual ICollection<Account> Accounts {get; set;}
...
}
class Account
{
public int Id {get; set;}
// every Account belongs to exactly one User, using foreign key:
public int UserId {get; set;}
public virtual User User {get; set;}
...
}
由于遵循惯例,实体框架会检测您的关系。它自动知道外键。它将确保您无法在没有用户的情况下创建帐户。
添加:确保某些值是唯一的
主键始终是唯一的。你不必担心这一点。
如果您希望其他项目是唯一的,这意味着这些值仍然可以更改,但如果您将数据库更改为已使用的值,则数据库不会接受它,您应该为其指定唯一的索引注释。这是在您的DbContext.OnModelCreating。
中完成的假设每个Email
在&#39;帐户&#39;的集合中必须是唯一的。您希望能够为其提供不同的值,但不允许为其提供已由其他Account
使用的值。
在你的DbContext中:
protected virtual OnModelCreating(DbModelBuilder modelBuilder)
{
// From table Accounts, give property Email a unique index annotation:
const string indexName = "indexEmails"
var indexAttribute = new IndexAttribute(indexName, 0) {IsUnique = true};
var indexAnnotation = new IndexAnnotation(indexAttribute);
propertyEmail = modelBuilder.Entity<Account>()
.Property(account => account.Email)
.HasColumnAnnotation(IndexAnnotation.AnnotationName, indexAnnotation);
...
}
您所做的就是说您应该将帐户的电子邮件属性放入索引中。索引的名称是&#34; indexEmails&#34;。索引中的所有值都应该是唯一的。
现在,无论何时您想添加或更新帐户,数据库都希望将电子邮件添加到索引中,并声明此电子邮件值尚未使用。
你在SaveChanges()期间得到了例外。
如果您希望两个值的组合是唯一的,则实例组合(电子邮件,密码)您必须为这两个属性提供具有相同名称的索引注释。
var entityAccount = modelBuilder.Entity<Account>();
var propertyEmail = entityAccount.Property(account => account.Email);
var propertyPassword = entityAccount.Property(account => account.Password);
// indes: first order by (0) email, then by (1) password
const string indexName = "IX_MyIndex");
var indexAttribute0 = new IndexAttribute(indexName, 0) {IsUnique = true};
var indexAnnotation0 = new IndexAnnotation(indexAttribute);
propertyEmail.HasUniqueIndexAcnnotation(IndexAnnotation.AnnotationName, indexAnnotation);
var indexAttribute1 = new IndexAttribute(indexName, 1) {IsUnique = true};
var indexAnnotation1 = new IndexAnnotation(indexAttribute);
propertyPassword.HasUniqueIndexAcnnotation(IndexAnnotation.AnnotationName, indexAnnotation);