2

このコードを希望どおりに機能させる方法についてのアイデアが不足しています。以下に示すように、3つのモデルがあります。

UserProfile and Player 一対一の関係

UserProfile が最初に作成され、登録時に emailConfirmation が提供されたユーザーの電子メールに送信されます。アカウントを確認すると、最初のログイン ページにリダイレクトされます。認証された場合は、新しいプレーヤーの作成ページにリダイレクトされ、拡張プロファイルに関する詳細情報が提供されます。作成ページUserIdで、ログインしているユーザーと作成しようとしているプレーヤーを同じにしたい。コードをそのまま試してみると、応答がなく、データベースに何も追加または保存されません。

Team and Player 一対多の関係

自明のことですが、プレイヤーはチームに所属している必要があります。これにより、編集アクションへのリダイレクトが行われなくなりますPlayer.TeamId != null

ユーザープロフィール

[Table("UserProfile")]
public class UserProfile
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    public string UserName { get; set; }

    public string Email { get; set; }

    public virtual Player Player { get; set; }
}

チーム

    public class Team
    {
    [Key]
    [HiddenInput(DisplayValue = false)]
    public int TeamId { get; set; }

    [Display(Name = "Full Name:")]
    public string Name { get; set; }         

    public virtual ICollection<Player> Players { get; set; }        
}

プレーヤー

public class Player
{
    [Key]
    [ForeignKey("UserProfile")]
    [HiddenInput(DisplayValue = false)]
    public int UserId { get; set; }

    [Required]
    [Display(Name = "Full name")]
    public string FullName{ get; set; }        

    [Display(Name = "Team")]
    public int TeamId { get; set; }

    public virtual Team Team { get; set; }

    public virtual UserProfile UserProfile { get; set; }
 }

プレーヤーの保存

public void SavePlayer(Player player)
    {
        using (var context = new EFootballDb())
        {
            if (player.UserId == 0)
            {
                context.Players.Add(player);
            }
            else if (player.UserId > 0)
            {
                 var currentPlayer = context.Players                        
                    .Single(t => t.UserId == player.UserId);

                context.Entry(currentPlayer).CurrentValues.SetValues(player);                    
            }
            context.SaveChanges();
        }
    }

アクションを作成

[HttpGet]
    public ActionResult Create()
    {
        PopulateTeamsDropDownList();
        return View();
    }

    [HttpPost]
    public ActionResult Create(Player model)
    {
       try
       {
           if (ModelState.IsValid)
           {
                _dataSource.SavePlayer(model);
                return RedirectToAction("Detail", "Team", new { id = model.TeamId });
            }
        }
        catch (Exception)
        {
            ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
        }
        PopulateTeamsDropDownList(model.TeamId);
        return View(model);
    }


private void PopulateTeamsDropDownList(object selectedTeams = null)
    {
        var teamsQuery = from d in _dataSource.Teams
                         orderby d.Name
                         select d;
        ViewBag.TeamID = new SelectList(teamsQuery, "TeamId", "Name", selectedTeams);
    }

すべてが問題なく動作しますが、Creation にリンクTeam and Playerできません。UserProfile and Player誰かが私が試すべきアイデアや別のアプローチを持っていますか? 前もって感謝します!

4

2 に答える 2

0

更新:これを行う別の方法を追加しています。これは非常に複雑な方法であり、機能しますが、最終的にはこれを望まないでしょう。

これは苦痛です。私もこれを理解するのに多くの時間を費やしました。私が見つけた最も近いオンライン リソースはhereでした。

そのページには 2 つのエラーがあることに注意してください。1) Create-Migration の代わりに Add-Migration を使用します。2) UsersContext を更新するときは、DbSet のジェネリック型を必ず含めてください。IE

public DbSet<Membership> Membership { get; set; }

そのリンクの手順に従ってください。その後、もう少し行く必要があります。

私のソリューションでは、すべてのモデルをモデル クラス ライブラリに移動し、UsersContext を DAL クラス ライブラリに移動しましたが、これは必須ではありません。

移行が完了したら、次のように UserProfile にリンクする基本クラスを追加できます ...

public class User
{
    public int UserId { get; set; }

    public string FirstName { get; set; }

    public int UserProfileId { get; set; }

    [ForeignKey("UserProfileId")]
    public UserProfile UserProfile { get; set; }
}

UsersContext を更新することを忘れないでください。注: UsersContext の名前は好きな名前に変更できます。

public DbSet<User> Users { get; set; }

最後のステップは、WebSecurity.CreateUserAndAccount(...) の代わりに AccountController で呼び出されるクラスを追加することです。

public class CustomSimpleMembershipProvider
{
    private readonly UsersContext _db = new UsersContext();

    public bool CreateUser(string username, string password, string firstName)
    {
        var userCreated = false;

        WebSecurity.CreateUserAndAccount(username, password);

        var userProfile = _db.UserProfiles.FirstOrDefault(u => u.UserName == username);

        // Check if user already exists
        if (userProfile != null)
        {
            var member = new Model.User { FirstName = firstName, UserProfile = userProfile };

            try
            {
                _db.Users.Add(member);
                _db.SaveChanges();

                userCreated = true;
            }
            catch (Exception)
            {
                //Add logging or throw whatever exceptions needed
                throw;
            }

        }
        return userCreated;
    }
}

移行の理由は、独自のコンテキストでメンバーシップ テーブルを制御できるようにするためです。私はそれらを別々のコンテキストで作成しようとしましたが、成功しませんでした。これで必要なものが得られることを願っています。

于 2013-02-28T20:57:52.227 に答える
0

これを行うより簡単な方法は、UserProfile への仮想外部キーを持つクラスを作成することです。Virtual は遅延読み込み用です。このようにした理由は、OAuth に到達すると、はるかに簡単に機能するようになるためです。

   public class User
    {
        public int Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public int UserProfileId { get; set; }

        [ForeignKey("UserProfileId")]
        public virtual UserProfile UserProfile { get; set; }
    }

次に、次のように、UsersContext を AccountModels.cs からカスタム コンテキストに移動します。

public class OAuthNoMigrateContext : DbContext
{
    public OAuthNoMigrateContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<User> Users { get; set; }
    public DbSet<UserProfile> UserProfiles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

    }
}

私の他の回答と同様の CustomSimpleMembershipProvider を作成します。

public class CustomSimpleMembershipProvider
{
    private readonly OAuthNoMigrateContext _db = new OAuthNoMigrateContext();

    public bool CreateUser(string username, string password, User user)
    {
        var userCreated = false;

        WebSecurity.CreateUserAndAccount(username, password);

        var userProfile = _db.UserProfiles.FirstOrDefault(u => u.UserName == username);

        // Check if user exists
        if (userProfile != null)
        {
            user.UserProfile = userProfile;

            try
            {
                _db.Users.Add(user);
                _db.SaveChanges();

                userCreated = true;
            }
            catch (Exception)
            {
                //Add logging or throw whatever exceptions needed
                throw;
            }

        }
        return userCreated;
    }
}

これを Application_Start に追加します

Database.SetInitializer(new OAuthNoMigrateInitializer());

注: ユーザーをチェックし、Application_Start から呼び出されるメソッドを作成したいと思います。最初に DB を呼び出すと、初期化が開始されます。

private static void ViewDb()
    {
        using (var context = new OAuthNoMigrateContext())
        {
            var user = context.Users.Where(u => u.FirstName.StartsWith("T"));
        }
    }

それはこのイニシャライザを呼び出します

public class OAuthNoMigrateInitializer : DropCreateDatabaseAlways<OAuthNoMigrateContext>
{
    private readonly CustomSimpleMembershipProvider _provider = new CustomSimpleMembershipProvider();

    protected override sealed void Seed(OAuthNoMigrateContext context)
    {
        //Initialize UserProfile
        WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);

        AddUsers(context);
    }

    private void AddUsers(OAuthNoMigrateContext context)
    {
        if (WebSecurity.UserExists("username")) return;

        var user = new User
        {
            FirstName = "FName",
            LastName = "LName"
        };

        _provider.CreateUser("username", "password", user);
    }
}
于 2013-03-27T17:59:29.523 に答える